c++ - Derive from `boost::static-visitor` to remove code duplication -
in 1 of projects i'm using boost-variant
excessively. @ point exceeded maximum number of template parameters (20) boost-variant
. hence, derived following solution linking several boost-variant
types linked-list.
#include <boost/variant.hpp> #include <iostream> template<int t> struct { const int value = t; }; 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); } }; struct intvisitor : public boost::static_visitor<int> { result_type operator()(const nextvar& n) { return n.apply_visitor(*this); } template<int t> result_type operator()(const a<t>& a) { return a.value; } }; template<int i> struct addvisitor : public boost::static_visitor<int> { result_type operator()(const nextvar& n) { return n.apply_visitor(*this); } template<int t> result_type operator()(const a<t>& a) { return a.value+i; } }; int main(int argc, char **args) { tvar x = a<35>(); printvisitor v1; std::cout << x.apply_visitor(v1) << std::endl; intvisitor v2; std::cout << x.apply_visitor(v2) << std::endl; addvisitor<10> v3; std::cout << x.apply_visitor(v3) << std::endl; }
i surprised how workaround solved problem. still there grain of salt. every visitor had include line:
result_type operator()(const nextvar& n) { return n.apply_visitor(*this); }
which seems kind of unnecessary code duplication. getting worse, if i'm in need of 60 or more types in boost-variant
. try define common base class of visitors:
template<typename t> struct basevisitor : public boost::static_visitor<t> { result_type operator()(const nextvar& n) { return n.apply_visitor(*this); } };
i thought, deriving basevisitor
shown below solve problem:
struct printvisitor : public basevisitor<std::string> { template<int t> result_type operator()(const a<t>& a) { return std::to_string(a.value); } };
but instead compiler complains:
template-argument "const a<t> &" not derived "t19"
what might closest workaround kind of problem?
first of all, increase limit of 20 fixed boost_mpl_limit_list_size
.
about code: if compiles, basevisitor::operator()
make infinite recursion besause of *this
considered basevisitor @ moment.
avoid that, can use crtp have derived()
instead:
template<class derived, typename t> struct basevisitor : public boost::static_visitor<t> { using typename boost::static_visitor<t>::result_type; derived & derived() { return static_cast<derived &>(*this); } result_type operator()(const nextvar& n) { return n.apply_visitor( derived() ); } };
then bringing same operator()
scope (otherwise hidden new one) of derived classes (as result_type
needed template classes).
without aliases
as said in comments, aliases have written in each derived class. rid of it, can gather 2 operator()
s @ same level in base class, , name derived function differently (visit
here):
template<class derived, typename t> struct basevisitor : public boost::static_visitor<t> { using typename boost::static_visitor<t>::result_type; derived & derived() { return static_cast<derived &>(*this); } result_type operator()(const nextvar& n) { return n.apply_visitor( derived() ); } template<int i> result_type operator()(const a<i>& a) { return derived().visit(a); } };
leaving with:
struct printvisitor : public basevisitor<printvisitor, std::string> { template<int i> std::string visit(const a<i>& a) { return std::to_string(a.value); } };
Comments
Post a Comment