2017-01-27 56 views
2

在我的項目中我詳盡地使用了boost::anyboost::variant。爲此,我在前一個問題Generic function to convert boost::any to boost::variant中設計了一個從boost::anyboost::variant的常規轉換程序。非常感謝幫助我的人們。提升任何使用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