2012-01-20 8 views
2
template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    T operator()(int& i) const { 
    try 
     { 
     return boost::lexical_cast<T>(i); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 

    T operator()(double& d) const { 
    try 
     { 
     return boost::lexical_cast<T>(d); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 

    // ... 
}; 

ご覧のとおり、operator()の実装コードはまったく同じです。コードを簡素化できる現実的な方法はありますか?boost :: static_vistorの派生クラスを簡略化する方法

は、コンパイラ(G ++)はerrorsのトンを生成しますコメントに基づいて更新

// //

template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    T operator()(T& i) const { 
    try 
     { 
     return boost::lexical_cast<T>(i); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 
}; 

ありがとうございます。 を見てわかるように、コンパイラは、コンパイル時間中にエラーまたは警告を生成しません:

/////はiammilindするiammilind

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <map> 
#include <boost/variant.hpp> 
#include <boost/lexical_cast.hpp> 

using namespace std; 

typedef boost::variant<int, double, string> VarIntDoubleString; 

// T is the result_type 
template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    template<typename U> 
    T operator()(U& i) const { 
    try 
     { 
     return boost::lexical_cast<T>(i); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 
}; 

int main(void) 
{ 
    map<string, VarIntDoubleString> mapValuesThree; 

    // store & retrieve char 
    mapValuesThree["char_fieldI"] = VarIntDoubleString('c'); 
    char fieldI = boost::apply_visitor(ClassVariantVisitor<char>(), mapValuesThree["char_fieldI"]); 
    cout << "fieldI: " << fieldI << endl; 
} 


~/Documents/C++/boost $ g++ -o p192f4 p192f4.cpp -Wall 
~/Documents/C++/boost $ ./p192f4 
terminate called after throwing an instance of 'char const*' 
aborted 
~/Documents/C++/boost $ g++ --version 
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 

からのコメントに基づいて2を更新しました。

//は3私はブースト:: MPLについての知識がないと、それを動作させることができないコンスタンチンOznobihin

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <map> 
#include <boost/variant.hpp> 
#include <boost/lexical_cast.hpp> 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/contains.hpp> 
#include <boost/utility/enable_if.hpp> 

using namespace std; 
template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    typedef boost::mpl::vector<int, double, string> VarIntDoubleString; 

    template <class U> 
    typename boost::enable_if< 
    typename boost::mpl::contains<VarIntDoubleString, U>::type, T>::type operator()(U &v) const 
    { 
    try 
     { 
     return boost::lexical_cast<T>(v); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 
}; 

int main(void) 
{ 
    map<string, ClassVariantVisitor::VarIntDoubleString> mapValuesThree; 

    // store & retrieve double 
    mapValuesThree["double_fieldJ"] = ClassVariantVisitor<double>::VarIntDoubleString(2.3456); 
    double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]); 
    cout << "fieldJ: " << fieldJ << endl; 

} 

からのコメントに基づいて更新します。 errors を参照してください。あなたのアイデアを使用して機能させるためにコードを修正する方法を教えてください。 はあなた

+0

テンプレートを使用できないのはなぜですか? –

+0

私は更新された投稿のあなたのコメントに対処しました。 – q0987

+2

@ q0987:あなたのテンプレートは間違っています。あなたは 'T'を再利用できません.iammilindのように' operator() 'テンプレートに新しいパラメータを指定する必要があります。私は 'char const *'を投げるという考えも批判します。 'boost :: bad_lexical_cast'がここに伝播するようにする方がはるかにクリーンです。 @MatthieuM。 –

答えて

3

使用テンプレート化演算子():: MPL:

 

template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    typedef boost::mpl::vector<int, double> source_types; 

    template <class U> 
    typename boost::enable_if< 
    typename boost::mpl::contains<source_types, U>::type, 
    T 
    >::type operator()(U &v) const { 
    try 
     { 
     return boost::lexical_cast<T>(v); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
}; 
 

UPDATE: あなたの場合boost :: variantを使用するとboost :: mpl :: vectorの代わりにtypesという入れ子型の配列を使うことができ、ClassVarの中にバリアントを定義する必要はありませんiantVisitorは、あなたのコードに基づいた最新のソリューションです:

 

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <map> 
#include <boost/variant.hpp> 
#include <boost/lexical_cast.hpp> 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/contains.hpp> 
#include <boost/utility/enable_if.hpp> 

using namespace std; 

typedef boost::variant<int, double, string> VarIntDoubleString; 

template<typename T> 
class ClassVariantVisitor : public boost::static_visitor<T> 
{ 
public: 
    template <class U> 
    typename boost::enable_if< 
    typename boost::mpl::contains<VarIntDoubleString::types, U>::type, T>::type operator()(U &v) const 
    { 
    try 
     { 
     return boost::lexical_cast<T>(v); 
     } 
    catch (boost::bad_lexical_cast& e) 
     { 
     throw e.what(); 
     } 
    } 
}; 

int main(void) 
{ 
    map<string, VarIntDoubleString> mapValuesThree; 

    // store & retrieve double 
    mapValuesThree["double_fieldJ"] = VarIntDoubleString(2.3456); 
    double fieldJ = boost::apply_visitor(ClassVariantVisitor<double>(), mapValuesThree["double_fieldJ"]); 
    cout << "fieldJ: " << fieldJ << endl; 
} 
 
+0

+1ホワイトリストアプローチのために: –

+0

@コンスタンチンOznobihin、私は私のOPを更新しました。私はそれを私のために働かせるためにあなたのさらなる助けが必要です。ありがとうございました – q0987

+0

@ q0987:私の編集を参照してください、mpl :: vectorはバリアントの代わりではなく、ビジターで許可されている型のコンテナでしたが、バリアントがある場合は追加のコンテナは必要ありません。 –

2

テンプレート化operator()ありがとう:ブーストiammilindが、フィルターの種類によって示唆されているように

template<typename U> 
T operator()(U& i) const { 
    try 
    { 
    return boost::lexical_cast<T>(i); 
    } 
    catch (boost::bad_lexical_cast& e) 
    { 
    throw e.what(); 
    } 
} 
+0

これは良い解決策ではありません。この方法で実装すると、コンパイラの時間チェックの利点が失われます。バリアントとコンパイラに 'char'型を格納するだけでコンパイル時に不平を言うことはありませんが、実行時には失敗します。 – q0987

+0

@ q0987:あなたはboost :: mplとenable_ifを使ってUを許される型の1つに制限することができます。サンプルの実装について私の答えを見てください。 –

+3

@ q0987、私はあなたの懸念を理解していません。これは間違いなくコンパイル時のチェックを行います。いくつかの型( 'char'のようなもの)を避けたいのであれば、単純にそれらをオーバーロードして' private'とunimplementedを保ちます。 – iammilind

関連する問題