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

2

11

I am designing a parser for verilog language, and one of the rule have 25 components, which I need a large boost::variant to hold it:

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 ; 

But g++ complain that the boost::variant can only hold no more than 20 types.

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;

I tries to redefine BOOST_VARIANT_LIMIT_TYPES to larger value:

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

But the error is still there,

Naidanaiditch answered 10/1, 2016 at 6:5 Comment(0)
S
11

The errors in clang++ and g++ in c++98 mode (what you seem to get) are pretty short (and sadly useless). In c++11 the error are way larger and reveal the key problem:

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

If you look in the Boost.MPL documentation you can see that you need to add:

#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_LIST_SIZE 30

You can only make the list have a size 30, 40 or 50 by default, if you want more you'll have to generate custom headers.

Running on Coliru

Scutum answered 10/1, 2016 at 6:6 Comment(4)
I have read this one when searching for answer, but I find it is from mpl, not variant. But anyway, it works, thank you very much.Naidanaiditch
But compilation slow down significantly, any suggestion?Naidanaiditch
I have no experience with this, but I think this question might help. Unfortunately I won't be able to test it until tonight (over 12 hours from now). Another possible suggestion could be to try to simplify the variant, for example using nested declaration, instantiation and construct variants if they make sense in your model.Scutum
I have revert back to use standard boost::variant with maximal 20 type, and I break my large variant to 2 smaller ones to fit in the 20 bound. The compilation improve by about 3 times.Naidanaiditch
P
1

I also stumbled upon the same problem. Unfortunately, I'm not able to use the solution above, as I'm dependent on other libraries already using boost-variant with #define BOOST_MPL_LIMIT_LIST_SIZE 20. Recompiling the boost-variant libraries waws also not a desired solution for me.

Hence, I devised a workaround for my problem. The following code illustrates the idea of this workaround with 39 types.

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;
}

The solution just creates a list of boost-variant types (similar to a linear list).

Pixilated answered 6/4, 2017 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.