22

文字列を数値データ型に変換する次の関数があります。

template <typename T>
bool ConvertString(const std::string& theString, T& theResult)
{
    std::istringstream iss(theString);
    return !(iss >> theResult).fail();
}

ただし、これは列挙型では機能しないため、次のようなことを行いました。

template <typename T>
bool ConvertStringToEnum(const std::string& theString, T& theResult)
{
    std::istringstream iss(theString);
    unsigned int temp;
    const bool isValid = !(iss >> temp).fail();
    theResult = static_cast<T>(temp);
    return isValid;
}

(私はtheStringが列挙型に対して有効な値を持っていると仮定しています。これは主に単純なシリアル化に使用しています)

これらの両方を組み合わせた単一の関数を作成する方法はありますか?

テンプレートの引数を少し試しましたが、何も思いつきませんでした。列挙型に対して1つの関数を呼び出し、他のすべてに対して別の関数を呼び出す必要がないのは良いことです。

ありがとうございました

4

2 に答える 2

43

あなたは2つのステップをしなければなりません。値を格納するのに十分な大きさの整数型を見つける。を使用できますunsigned longが、値が負になる可能性があります。次に、を使用できますlongが、値はの範囲に拡張できますunsigned long。したがって、実際にはすべてに適合するタイプはありません。

ただし、過負荷解決を使用することによるトリックがあります。はい、これ

template<typename T>
struct id { typedef T type; };

id<char[1]>::type &find_etype(int);
id<char[2]>::type &find_etype(unsigned int);
id<char[3]>::type &find_etype(long);
id<char[4]>::type &find_etype(unsigned long);

カバーするように、long longまたはunsigned long long実装がそれをサポートしている場合は、適切に変更できます。さて、列挙型を渡すと、他のすべての型よりもこれらの1つが優先されます。これは、そのすべての値を格納できる型です。sizeofリターンタイプをテンプレートに渡す必要があります。

template<int> struct get_etype;
template<> struct get_etype<1> { typedef int type; };
template<> struct get_etype<2> { typedef unsigned int type; };
template<> struct get_etype<3> { typedef long type; };
template<> struct get_etype<4> { typedef unsigned long type; };

今、あなたは正しいタイプを得ることができます。ここで必要なのは、あるタイプが列挙型であるかどうかを確認することだけです。これを行う方法は、「C ++テンプレート-完全なガイド」という本で説明されていますが、残念ながら、非常に多くのコードが含まれています。だから私はブーストを使用しますis_enum。まとめると、次のようになります。

template <typename T>
typename boost::disable_if< boost::is_enum<T>, bool>::type 
ConvertString(const std::string& theString, T& theResult)
{
    std::istringstream iss(theString);
    return !(iss >> theResult).fail();
}

template <typename T>
typename boost::enable_if< boost::is_enum<T>, bool>::type 
ConvertString(const std::string& theString, T& theResult)
{
    typedef typename get_etype<sizeof find_etype(theResult)>::type 
      safe_type;

    std::istringstream iss(theString);
    safe_type temp;
    const bool isValid = !(iss >> temp).fail();
    theResult = static_cast<T>(temp);
    return isValid;
}

お役に立てれば。

于 2009-10-06T22:29:44.057 に答える
10

そして、質問を「完了する」ために、C++0xでは次のようにすることができます。

typedef typename std::underlying_type<T>::type safe_type;

ヨハネスのget_etypeトリックの代わりに。

于 2011-01-22T20:56:57.027 に答える