2017-01-30 12 views
1

私は現在、個人用の標準入力リーダーを実装しようとしています。私は、標準入力から整数を読み込み、その妥当性をチェックするメソッドを作成しました。アイデアは、標準入力から文字列を読み込み、いくつかのチェックを行い、intに変換し、最後のチェックを行い、読み込まれた値を返します。その間に何らかのエラーが発生した場合は、errorHintを入力してstd::cerrに印刷し、std::numeric_limits<int>::min()に返信します。C++ std :: string to number template

私はこのアイデアを実装するのがとても簡単で簡単だと思っています。今ではコンセプトを一般化してメソッドテンプレートを作成したかったので、標準入力から読み込む必要があるときはいつでもコンパイル時に選択できました整数が必要です(intlonglong longunsigned 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を使用するのではなく、例外をスローする方が良いと思われますか?特に私はあなた自身のエラータイプを作成し、失敗の場合にそれを投げることを提案するのは正しいでしょうか? – Francesco

    +1

    @ user2271691理想的には、std :: runtime_errorまたはstd :: invalid_argumentから派生した独自のエラータイプです。 –