2017-01-30 1 views
1

현재 개인용 표준 입력 판독기를 구현하려고합니다. 표준 입력에서 정수를 읽고 유효성을 검사하는 메소드를 만들었습니다. 아이디어는 표준 입력에서 문자열을 읽고, 여러 검사를하고, int로 변환하고, 마지막 검사를 수행하고, 읽은 값을 반환한다는 것입니다. 한편 오류가 발생하면 errorHint을 채워 std::cerr에 인쇄하고 std::numeric_limits<int>::min()을 반환합니다.C++ std :: number 템플릿에 문자열

생각은 간단하고 구현하기 쉽습니다. 지금은 컨셉을 일반화하고 메소드 템플릿을 만들고 싶었습니다. 기본적으로 표준 입력에서 읽을 때마다 컴파일 타임에 선택할 수있었습니다. 정수 내가 원하는 (그것은 int, long, long long, unsigned long 등등하지만 정수 일 수 있습니다).

template< 
    class T, 
    class = typename std::enable_if<std::is_integral<T>::value, T>::type 
> 
static T getIntegerTest(std::string& strErrorHint, 
         T nMinimumValue = std::numeric_limits<T>::min(), 
         T nMaximumValue = std::numeric_limits<T>::max()); 

아래 같은 .HPP 파일 몇 줄의 구현 :

template< 
    class T, 
    class> 
T InputReader::getIntegerTest(std::string& strErrorHint, 
           T nMinimumValue, 
           T nMaximumValue) 
{ 
    std::string strInputString; 
    std::cin >> strInputString; 

    // Do several checks 

    T nReturnValue = std::stoi(strInputString); /// <--- HERE!!! 

    // Do other checks on the returnValue 

    return nReturnValue; 
} 

지금 문제가

, 나는 변환 할이를 위해 나는 다음과 같은 정적 템플릿 방법을 만들었습니다 방금 읽고 알았던 문자열이 정수 유형 T의 올바른 범위 내에 있습니다. 나는 이것을 어떻게 좋은 방법으로 할 수 있는가?

+1

'bool success = std :: cin >> T_instance;', 다음 (다른) 범위 검사 ... – LogicStuff

+1

단순히'std :: istringstream'을 사용하지 않는 이유는 무엇입니까? –

답변

2

함수 개체를 특수화하는 것은 형식 특성을 기반으로 동작을 수정하는 매우 다양한 방법입니다.

접근 방식은 다음과 같습니다

  1. 조작

  2. 에 대한 일반적인 템플릿을 정의 전문 코너 케이스의 템플릿 도우미 함수

통해

  • 전화 예 :

    #include <iostream> 
    #include <type_traits> 
    #include <string> 
    
    
    namespace detail { 
    /// general case 
        template<class Integer, typename Enable = void> 
        struct convert_to_integer { 
         Integer operator()(std::string const &str) const { 
          return std::stoi(str); 
         } 
        }; 
    
    // special cases 
        template<class Integer> 
        struct convert_to_integer<Integer, std::enable_if_t<std::is_same<long, Integer>::value> > { 
         long operator()(std::string const &str) const { 
          return std::stol(str); 
         } 
        }; 
    } 
    
    template<class T, class StringLike> 
    T to_integral(StringLike&& str) 
    { 
        using type = std::decay_t<T>; 
        return detail::convert_to_integer<type>()(str); 
    }; 
    
    int main() { 
    
        std::string t1 = "6"; 
        const char t2[] = "7"; 
    
        std::cout << to_integral<int>(t1) << std::endl; 
        std::cout << to_integral<int>(t2) << std::endl; 
    
        // will use the specilaisation 
        std::cout << to_integral<long>(t1) << std::endl; 
        std::cout << to_integral<long>(t2) << std::endl; 
    
        // will use the default case 
        std::cout << to_integral<short>(t1) << std::endl; 
        std::cout << to_integral<short>(t2) << std::endl; 
    } 
    

    p.s. 오류보고 전략은 효과가 있어야합니다. std::runtime_error 던지기를 제안하십시오.

  • +0

    @ Richard Hodges의 답변 주셔서 감사합니다! 아주 좋아! 나는 많이 감사한다! 예외에 대해서는 왜 errorHint를 사용하는 대신에 예외를 throw하는 것이 더 낫다고 생각합니까? 특히 나는 당신이 내 자신의 오류 유형을 생성하고 실패의 경우 그 중 하나를 던질 것을 제안 것이 맞을 것 같아요? – Francesco

    +1

    @ user2271691 std :: runtime_error 또는 std :: invalid_argument에서 파생 된 사용자 자신의 오류 유형이 이상적입니다. –

    관련 문제