如何增加 boost::variant 可以处理的类型数量

how to increase the number of types that can handled by boost::variant

我正在为 verilog 语言设计一个解析器,其中一个规则有 25 个组件,我需要一个大 boost::variant 来容纳它:

typedef boost::variant<
 shared_ptr<T_module_item__port_declaration>
 ,  shared_ptr<T_module_item__generate_region>
 ,  shared_ptr<T_module_item__specify_block>
 ,  shared_ptr<T_module_item__parameter_declaration>
 ,  shared_ptr<T_module_item__specparam_declaration>
 ,  shared_ptr<T_module_item__net_declaration>
 ,  shared_ptr<T_module_item__reg_declaration>
 ,  shared_ptr<T_module_item__integer_declaration>
 ,  shared_ptr<T_module_item__real_declaration>
 ,  shared_ptr<T_module_item__time_declaration>
 ,  shared_ptr<T_module_item__realtime_declaration>
 ,  shared_ptr<T_module_item__event_declaration>
 ,  shared_ptr<T_module_item__genvar_declaration>
 ,  shared_ptr<T_module_item__task_declaration>
 ,  shared_ptr<T_module_item__function_declaration>
 ,  shared_ptr<T_module_item__local_parameter_declaration>
 ,  shared_ptr<T_module_item__parameter_override>
 ,  shared_ptr<T_module_item__continuous_assign>
 ,  shared_ptr<T_module_item__gate_instantiation>
 ,  shared_ptr<T_module_item__udp_instantiation>
 ,  shared_ptr<T_module_item__module_instantiation>
 ,  shared_ptr<T_module_item__initial_construct>
 ,  shared_ptr<T_module_item__always_construct>
 ,  shared_ptr<T_module_item__loop_generate_construct>
 ,  shared_ptr<T_module_item__conditional_generate_construct>
 > module_item ; 

但是 g++ 抱怨 boost::variant 只能容纳不超过 20 种类型。

verilogast.h|1129 col 2| error: wrong number of template arguments (25, should be 20)
||   > module_item ; 
||   ^
/usr/include/boost/variant/variant_fwd.hpp|213 col 53| error: provided for ‘template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15, class T16, class T17, class T18, class T19> class boost::variant’
||  template < BOOST_VARIANT_AUX_DECLARE_PARAMS > class variant;

我尝试将 BOOST_VARIANT_LIMIT_TYPES 重新定义为更大的值:

#define BOOST_VARIANT_LIMIT_TYPES 30
#include<boost/variant.hpp>

但是错误依旧,

c++98 模式下 clang++ 和 g++ 的错误(您似乎得到的)非常短(遗憾的是没有用)。 在 c++11 中,错误更大并揭示了关键问题:

error: too many template arguments for class template 'list'
typedef typename mpl::list< T... >::type type;

如果您查看 Boost.MPL documentation,您会发现您需要添加:

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_LIST_SIZE 30

默认情况下,您只能使列表的大小为 30、40 或 50,如果您想要更多,则必须生成自定义 headers。

Running on Coliru

我也遇到了同样的问题。不幸的是,我无法使用上面的解决方案,因为我依赖于其他已经使用 boost-variant#define BOOST_MPL_LIMIT_LIST_SIZE 20 的库。重新编译 boost-variant 库 waws 也不是我想要的解决方案。

因此,我设计了一个解决方法来解决我的问题。以下代码用 39 种类型说明了此解决方法的想法。

typedef boost::variant<
    A<20>,A<21>,A<22>,A<23>,A<24>,A<25>,A<26>,A<27>,A<28>,A<29>,A<30>,A<31>,A<32>,A<33>,A<34>,A<35>,A<36>,A<37>,A<38>,A<39>
> NextVar;

typedef boost::variant<
    A<1>,A<2>,A<3>,A<4>,A<5>,A<6>,A<7>,A<8>,A<9>,A<10>,A<11>,A<12>,A<13>,A<14>,A<15>,A<16>,A<17>,A<18>,A<19>,NextVar
> TVar;

struct PrintVisitor : public boost::static_visitor<std::string> {
    result_type operator()(const NextVar& n) {
        return n.apply_visitor(*this);
    }

    template<int T>
    result_type operator()(const A<T>& a)  {
        return std::to_string(a.value);
    }
};

int main(int argc, char **args) {
    TVar x = A<35>(); // Implicit conversion! Great!
    PrintVisitor v;
    std::cout << x.apply_visitor(v) << std::endl;
}

该解决方案仅创建一个 boost-variant 类型的列表(类似于线性列表)。