【问题标题】:Boost Any to Boost Variant using Boost Preprocessor使用 Boost Preprocessor Boost Any to Boost Variant
【发布时间】:2017-01-27 08:45:55
【问题描述】:

在我的项目中,我用尽了boost::anyboost::variant。为此,在我之前的问题Generic function to convert boost::any to boost::variant 中设计了一个从boost::anyboost::variant 的通用转换例程。非常感谢帮助我的人。

找到的解决方案对我来说没有任何问题,但有一些严重的缺陷。完全模板化的解决方案产生的代码膨胀可能会令人望而却步,有时对于简单的转换是不必要的。 (我没有提到编译时间。)

现在我有了让模板专业化为简单(非通用)转换工作的想法,但我发现必要的代码繁琐且容易输入错误。特别是,如果必须一遍又一遍地完成这项任务。

下面的代码 sn-p 说明了这个问题。在典型应用程序中可能有多达 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)

但我怀疑这个解决方案是否可行。

【问题讨论】:

  • 所以,明确一点,宏的目标是生成模板特化的定义,不是当场转换成boost::any
  • 你明白了。宏应该只生成上面的代码。

标签: c++ templates boost-variant boost-preprocessor boost-any


【解决方案1】:

给你:

#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

【讨论】:

  • 非常感谢。我会检查你的解决方案。看来我真的必须多处理一点boost-preprocessor。解决方案比我预期的要短得多。
  • 我什至不知道 BOOST_PP_REMOVE_PARENS!这已经是我未能取得进展的地方了。
  • @FrankSimon 我想你也可以使用BOOST_PP_SEQ_ENUM(typeSeq)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多