2017-01-27 23 views
2

私のプロジェクトでは、boost::anyboost::variantを網羅的に使用しています。このために、以前の質問Generic function to convert boost::any to boost::variantでは、boost::anyからboost::variantまでの一般的な変換ルーチンが考案されました。人々を助けてくれてありがとう。ブーストプリプロセッサを使用したBoost Any Boostバリアント

見つかった解決策は問題なく機能しましたが、重大な欠点がありました。完全にテンプレート化されたソリューションによって生成されたコードの膨らみは、禁止されている可能性があり、単純な変換には不要なことがあります。

簡単な(一般的ではない)変換ではテンプレートの特殊化が機能するようになりましたが、面倒でエラーが発生しやすいタイプのコードが見つかりました。特に、この作業を何度も何度もやり直さなければならない場合。

次のコードスニペットは、この問題を示しています。典型的なアプリケーションでは、20種類以上の画像があるかもしれないというイメージ!

#include <boost/preprocessor.hpp> 
#include <boost/variant.hpp> 
#include <boost/any.hpp> 
#include <boost/optional.hpp> 
#include <iostream> 

template<typename VARIANT> 
boost::optional<VARIANT> anyToVariant(const boost::any& any) { 
    boost::optional<VARIANT> ret; 
    // General implementation omitted. 
    // The implementation is lengthy and produces an enormous code bloat. In some cases it is the best solution. 
    return ret; 
} 

// Specialized Template reduces code bloat. But is error-prone to type write for every new variant type. 
template<> 
boost::optional <boost::variant<int, double, std::string>> anyToVariant(const boost::any& any) { 
    boost::optional<boost::variant<int, double, std::string>> ret; 
    if (any.type() == typeid(int)) { 
     ret = boost::any_cast<int>(any); 
    } 
    if (any.type() == typeid(double)) { 
     ret = boost::any_cast<double>(any); 
    } 
    if (any.type() == typeid(std::string)) { 
     ret = boost::any_cast<std::string>(any); 
    } 
    return ret; 
} 

// Should be implemented with boost preprocessor 
#define BOOST_ANY_TO_VARIANT(TypeList) 

// Better would be a macro like this 
BOOST_ANY_TO_VARIANT(int, double, std::string); // Create the above template specialization 

int main() { 
    boost::variant<int, double, std::string> v; 
    boost::any x = 4; 
    v=*anyToVariant<boost::variant<int, double, std::string>>(x); 
} 

よりよい解決策はもちろん、マクロだろうが、残念ながら私はboost-preprocessorでこのマクロを実装することができませんでした。私はまだスキルが不足していますが、それができると確信しています。

経験がある方はboost-preprocessorで問題を解決できますか?

私が想像できる最良の解決策は、以下のようなマクロのようになります。

#define BOOST_ANY_TO_VARIANT(VariantType) \ 
// Magic? 

typedef boost::variant<int, std::string, double> MyVariant; 

BOOST_ANY_TO_VARIANT(MyVariant) 

しかし、私は、このソリューションが実現可能であることを疑います。

+0

を、ちょうど明確にするために、マクロの目標は、テンプレートの特殊化の定義を生成することで、 *現場では 'boost :: any'を変換しませんか? – Quentin

+0

あなたはそれを持っています。マクロは上記のコードを生成します。 – Aleph0

答えて

2

ここに行く:

#define ANY_TO_VARIANT_OP_VARIANT(typeSeq) \ 
    boost::optional<boost::variant<BOOST_PP_SEQ_ENUM(typeSeq)>> 

#define ANY_TO_VARIANT_CONVERT_AND_RETURN(r, data, elem) \ 
    if (any.type() == typeid(elem)) { \ 
     return Ret{boost::any_cast<elem>(any)}; \ 
    } 

#define SPECIALIZE_BOOST_ANY_TO_VARIANT(typeSeq) \ 
    template<> \ 
    ANY_TO_VARIANT_OPT_VARIANT(typeSeq) anyToVariant(const boost::any& any) { \ 
     using Ret = ANY_TO_VARIANT_OPT_VARIANT(typeSeq); \ 
     BOOST_PP_SEQ_FOR_EACH(ANY_TO_VARIANT_CONVERT_AND_RETURN, ~, typeSeq) \ 
     return Ret{}; \ 
    } 

使用法:だから

SPECIALIZE_BOOST_ANY_TO_VARIANT((int)(double)(std::string)) 

See it live on Coliru

+0

多くのありがとう。あなたの解決策を確認します。私は本当に 'boost-preprocessor'をもう少し扱わなければならないようです。解決策は私が期待するほど短かった。 – Aleph0

+0

私はBOOST_PP_REMOVE_PARENSについて知らなかった!これはすでに私が進展していない点でした。 – Aleph0

+0

@FrankSimon私はあなたも 'BOOST_PP_SEQ_ENUM(typeSeq)'を使うことができると思います。 – llonesmiz

関連する問題