Unable to access template objects using boost::apply_visitor - c++

I am learning about boost::variant and accessing its members using apply_visitor. So, I wrote the following example.
I have pointers to templated objects as my class members. I would like to access them using apply_visitor.
//Example program
#include <iostream>
#include <map>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
#include <boost/any.hpp>
class A {
template<size_t dim>
struct C : boost::static_visitor<C<dim> *>{
int x;
C() {
x = dim;
}
template <size_t t>
C<t> * operator()(C<t> *s) const {
std::cout<<s->x<<std::endl;
return s;
}
};
public:
C<1>* Aasd;
C<2>* Bbsd;
std::map<std::string, boost::variant<C<2> *, C<1> * > > matrices;
A() {
Aasd = new C<1>;
Bbsd = new C<2>;
matrices.insert(std::make_pair("Bb", Bbsd));
boost::apply_visitor(C<2>(), matrices["Bb"]);
// boost::apply_visitor(C<1>(), matrices["Aa"]);
}
~A() {
delete Aasd;
delete Bbsd;
}
};
int main()
{
A a;
return 0;
}
The error that I get from compiling the above is
In file included from /usr/include/boost/variant.hpp:17:0,
from 8:
/usr/include/boost/variant/variant.hpp: In instantiation of 'boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = A::C<1ul>*; Visitor = const A::C<2ul>; boost::detail::variant::invoke_visitor<Visitor>::result_type = A::C<2ul>*]':
/usr/include/boost/variant/detail/visitation_impl.hpp:130:9: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor<const A::C<2ul> >; VoidPtrCV = void*; T = A::C<1ul>*; typename Visitor::result_type = A::C<2ul>*; mpl_::true_ = mpl_::bool_<true>]'
/usr/include/boost/variant/detail/visitation_impl.hpp:173:9: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<const A::C<2ul> >; VoidPtrCV = void*; T = A::C<1ul>*; NoBackupFlag = boost::variant<A::C<2ul>*, A::C<1ul>*>::has_fallback_type_; typename Visitor::result_type = A::C<2ul>*]'
/usr/include/boost/variant/detail/visitation_impl.hpp:256:5: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>; step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, A::C<2ul>*, boost::mpl::l_item<mpl_::long_<1l>, A::C<1ul>*, boost::mpl::l_end> > >, boost::mpl::l_iter<boost::mpl::l_end> >; Visitor = boost::detail::variant::invoke_visitor<const A::C<2ul> >; VoidPtrCV = void*; NoBackupFlag = boost::variant<A::C<2ul>*, A::C<1ul>*>::has_fallback_type_; typename Visitor::result_type = A::C<2ul>*; mpl_::false_ = mpl_::bool_<false>]'
/usr/include/boost/variant/variant.hpp:2367:13: required from 'static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<const A::C<2ul> >; VoidPtrCV = void*; T0_ = A::C<2ul>*; T1 = A::C<1ul>*; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename Visitor::result_type = A::C<2ul>*]'
/usr/include/boost/variant/variant.hpp:2378:13: required from 'typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::invoke_visitor<const A::C<2ul> >; T0_ = A::C<2ul>*; T1 = A::C<1ul>*; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename Visitor::result_type = A::C<2ul>*]'
/usr/include/boost/variant/variant.hpp:2401:52: required from 'typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::apply_visitor(Visitor&) [with Visitor = const A::C<2ul>; T0_ = A::C<2ul>*; T1 = A::C<1ul>*; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename Visitor::result_type = A::C<2ul>*]'
/usr/include/boost/variant/detail/apply_visitor_unary.hpp:76:43: required from 'typename Visitor::result_type boost::apply_visitor(const Visitor&, Visitable&) [with Visitor = A::C<2ul>; Visitable = boost::variant<A::C<2ul>*, A::C<1ul>*>; typename Visitor::result_type = A::C<2ul>*]'
34:51: required from here
/usr/include/boost/variant/variant.hpp:1048:32: error: cannot convert 'A::C<1ul>*' to 'boost::detail::variant::invoke_visitor<const A::C<2ul> >::result_type {aka A::C<2ul>*}' in return
return visitor_(operand);
It compiles and works fine if I remove C<1> * from the boost::variant declaration.
Any suggestions would be highly appreciated.

All visitor functions must follow the scheme defined by base class: boost::static_visitor<C<dim> *>.
That means return value of operator() must be always C<dim> * not C<t>* - see:
template<size_t dim>
struct C : boost::static_visitor<C<dim> *> {
template <size_t t>
C<dim> * operator()(C<t> *s) const {
// ^^^ - not t, must be as static_visitor parameter few lines above
std::cout<<s->x<<std::endl;
return s; // of course this part will have problems to compile
// e.g. pointers to C<2> and C<1> are not convertible
}
As I put in comments in right of return s- this does not compile - because compiler cannot covert C<1> to C<2>.
What you might do to solve this, is to introduce base class - like below:
struct CBase {
int x;
};
template<size_t dim>
struct C : CBase, boost::static_visitor<CBase*> {
C() : CBase{dim} {}
template <size_t t>
CBase* operator()(C<t> *s) const {
std::cout<<s->x<<std::endl;
return s;
}

Related

unable to return a std::vector of boost::variant of std::unique_ptr

I'm writing a small C++ module for Python. In this module I set connection to different databases. Connection to one of those databases is set like so:
std::unique_ptr<R::Connection> conn = R::connect("localhost", 28015);
After I set connection, I want to return this connection variable. The way I do it is using vector and variant (since I may return multiple things in a vector - database connection, some extra parameters etc).
This is how I define variant and vector types:
typedef variant<std::unique_ptr<R::Connection>,....connections to other databases> VariantData;
typedef std::vector<VariantData> vector;
And, finally, this is how I return a vector right after I set connection:
return vector{conn, ""};
As a result, I get a long list of errors. However, this trick works well with other clients which set connections to other databases and do not use unique_ptr. So, I think I need something like casting std::unique_ptr<R::Connection> to Connection * or something like that, to be able to use conn variable like a general pointer.
EDIT
With these snippets of code:
typedef variant<R::Connection * ,....connections to other databases> VariantData;
typedef std::vector<VariantData> vector;
... function body
... code which does not matter
std::unique_ptr<R::Connection> conn = R::connect("localhost", 28015);
return vector{move(conn),""};
And this is the error messages I get:
n file included from /usr/include/boost/variant.hpp:17:0,
from corm.cpp:4:
/usr/include/boost/variant/variant.hpp: In instantiation of ‘typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&&, int, mpl_::false_) [with T = std::unique_ptr<RethinkDB::Connection>; T0_ = mysqlpp::Connection*; T1 = mongo::DBClientBase*; T2 = pqxx::basic_connection<pqxx::connect_direct>*; T3 = sqlite3**; T4 = IBPP::Ptr<IBPP::IDatabase>; T5 = RethinkDB::Connection*; T6 = const char*; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type = void; mpl_::false_ = mpl_::bool_<false>]’:
/usr/include/boost/variant/variant.hpp:1789:62: required from ‘boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(T&&, typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type*, typename boost::disable_if<boost::is_const<FunctionObj> >::type*) [with T = std::unique_ptr<RethinkDB::Connection>; T0_ = mysqlpp::Connection*; T1 = mongo::DBClientBase*; T2 = pqxx::basic_connection<pqxx::connect_direct>*; T3 = sqlite3**; T4 = IBPP::Ptr<IBPP::IDatabase>; T5 = RethinkDB::Connection*; T6 = const char*; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type = void; typename boost::disable_if<boost::is_const<FunctionObj> >::type = void]’
corm.cpp:94:39: required from here
/usr/include/boost/variant/variant.hpp:1615:17: error: no matching function for call to ‘boost::variant<mysqlpp::Connection*, mongo::DBClientBase*, pqxx::basic_connection<pqxx::connect_direct>*, sqlite3**, IBPP::Ptr<IBPP::IDatabase>, RethinkDB::Connection*, const char*>::initializer::initialize(void*, boost::remove_reference<std::unique_ptr<RethinkDB::Connection>&>::type)’
)
^
/usr/include/boost/variant/variant.hpp:1615:17: note: candidates are:
In file included from /usr/include/boost/variant/variant.hpp:33:0,
from /usr/include/boost/variant.hpp:17,
from corm.cpp:4:
/usr/include/boost/variant/detail/initializer.hpp:104:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >,
>::initializer_node::param_T {aka RethinkDB::Connection* const&}’
Makefile:45: recipe for target 'corm.o' failed
make: *** [corm.o] Error 1
EDIT
This is the code (minimized)
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/variant.hpp>
#include <vector>
#include <memory>
#include <rethinkdb.h>
using namespace boost;
using namespace boost::python;
namespace Ret = RethinkDB;
typedef variant<Ret::Connection *, const char*> VariantData;
typedef std::vector<VariantData> vector;
class ORM{
private:
int idx;
public:
ORM(int _idx){
this->idx = _idx;
}
vector Connect(){
if(this->idx == 8){
std::unique_ptr<Ret::Connection> conn = Ret::connect(this->host, this->port);
return vector{std::move(conn), ""};
}
}
};
struct variant_to_object:static_visitor<PyObject*>{
static result_type convert(VariantData const& v){
return apply_visitor(variant_to_object(), v);
}
template<typename T>
result_type operator () (T const& v) const{
return incref(object(v).ptr());
}
};
BOOST_PYTHON_MODULE(corm){
class_<vector>("vector").def(vector_indexing_suite<vector, true>());
to_python_converter<VariantData, variant_to_object>();
implicitly_convertible<Ret::Connection *, VariantData>();
implicitly_convertible<const char*, VariantData>();
class_<ORM>("ORM",
init<int>())
.def("Connect", &ORM::Connect);
}
Client for rethinkdb is taken from here.

Using boost::make_recursive_variant with tuple

boost::make_recursive_variant is intended to make variants which are recursive, without requiring the creation of an intermediate type by using the tag type boost::recursive_variant_. For std::vector<recursive_variant_> this appears to work fine, however for a std::tuple<int, recursive_variant_> it fails.
Example:
#include <type_traits>
#include <tuple>
#include <vector>
#include <boost/variant.hpp>
using std::cout;
using std::vector;
using std::tuple;
using boost::variant;
using boost::static_visitor;
using boost::apply_visitor;
using boost::make_recursive_variant;
using boost::recursive_variant_;
using A = typename make_recursive_variant<
int,
vector<recursive_variant_>
>::type;
using B = vector<A>;
using C = typename make_recursive_variant<
int,
tuple<int, recursive_variant_>
>::type;
using D = tuple<int, C>;
int main(int, char**)
{
A a = 0;
B b{1, 2};
a = b;
C c = 0;
D d{0, 1};
//c = d;
}
If the last line is uncommented, the program no longer compiles. Is this a usage error (and if yes, how so?), or is it bug or limitation in boost::tuple?
Error message (on mingw-w64 with gcc 4.8.1):
In file included from D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant.hpp:17:0,
from D:\projects\test\main.cpp:4:
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp: In instantiation of 'void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&, int, mpl_::false_) [with T = const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >; T0_ = boost::detail::variant::recursive_flag<int>; T1 = std::tuple<int, boost::recursive_variant_>; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; mpl_::false_ = mpl_::bool_<false>]':
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:1703:38: required from 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(const T&) [with T = std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >; T0_ = boost::detail::variant::recursive_flag<int>; T1 = std::tuple<int, boost::recursive_variant_>; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]'
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:2129:29: required from 'void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::assign(const T&) [with T = std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >; T0_ = boost::detail::variant::recursive_flag<int>; T1 = std::tuple<int, boost::recursive_variant_>; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]'
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:2168:19: required from 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>& boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::operator=(const T&) [with T = std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >; T0_ = boost::detail::variant::recursive_flag<int>; T1 = std::tuple<int, boost::recursive_variant_>; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]'
D:\projects\test\main.cpp:37:4: required from here
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:1557:17: error: no matching function for call to 'boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>::initializer::initialize(void*, const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >&)'
)
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:1557:17: note: candidates are:
In file included from D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/variant.hpp:31:0,
from D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant.hpp:17,
from D:\projects\test\main.cpp:4:
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:104:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node, mpl_::int_<1> >; Iterator = boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T = const std::tuple<int, boost::recursive_variant_>&]
static int initialize(void* dest, param_T operand)
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:104:24: note: no known conversion for argument 2 from 'const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node, mpl_::int_<1> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > >::initializer_node::param_T {aka const std::tuple<int, boost::recursive_variant_>&}'
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:115:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node, mpl_::int_<1> >; Iterator = boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T = std::tuple<int, boost::recursive_variant_>&&]
static int initialize(void* dest, param2_T operand)
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:115:24: note: no known conversion for argument 2 from 'const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node, mpl_::int_<1> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > >::initializer_node::param2_T {aka std::tuple<int, boost::recursive_variant_>&&}'
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:149:17: note: static void boost::detail::variant::initializer_root::initialize()
static void initialize();
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:149:17: note: candidate expects 0 arguments, 2 provided
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:115:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >; Iterator = boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T = int&&]
static int initialize(void* dest, param2_T operand)
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:115:24: note: no known conversion for argument 2 from 'const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node::param2_T {aka int&&}'
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:104:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >; Iterator = boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T = const int&]
static int initialize(void* dest, param_T operand)
^
D:/libs/3rdparty-prebuild-vc11-win64/vc11/win64/boost-1_54_0-vc11-win64/include/boost-1_54/boost/variant/detail/initializer.hpp:104:24: note: no known conversion for argument 2 from 'const std::tuple<int, boost::variant<boost::detail::variant::recursive_flag<int>, std::tuple<int, boost::recursive_variant_>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, std::tuple<int, boost::recursive_variant_>, boost::mpl::l_end> > > >::initializer_node::param_T {aka const int&}'
The problem is that make_recursive_variant isn't aware of variadic templates, so it doesn't know to expand recursive_variant_ within std::tuple<..., recursive_variant_>.
You can test this by changing std::tuple to std::pair (a fixed-adic template) and observing that that works fine.
As a workaround, you can teach Boost.Variant how to expand within variadic templates with the following snippet (place at the top level of your source file):
namespace boost { namespace detail { namespace variant {
template<template<typename...> class F, typename... Ts, typename Dest, typename Source>
struct substitute<
F<Ts...>
, Dest
, Source
BOOST_MPL_AUX_LAMBDA_ARITY_PARAM(mpl::int_<-1>)
>
{
typedef F<typename substitute<
Ts, Dest, Source
>::type...> type;
};
}}} // namespace boost::detail::variant
Edit: I've put in a pull request: https://github.com/boostorg/variant/pull/2

boost::variant< boost::shared_ptr<T> > won't compile

The following code fails to compile with g++ 4.7.3 when the -std=c++11 flag is set (error message pasted at the bottom):
#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>
int main() {
boost::shared_ptr<int> i;
boost::variant< boost::shared_ptr<int> > v;
v = i;
return 0;
}
The Boost version is 1.54. It compiles without error when std=c++11 is not set and also with clang 3.4 (with or without -std=c++11). I'm pretty sure this should be valid code, so is this a g++ problem or a boost problem? If so, what is the bug, exactly?
Here's the error message:
In file included from /usr/local/include/boost/variant.hpp:17:0,
from vartest.cpp:1:
/usr/local/include/boost/variant/variant.hpp: In instantiation of ‘void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::move_assigner::internal_visit(RhsT&, int) [with RhsT = boost::shared_ptr<int>; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]’:
/usr/local/include/boost/variant/detail/visitation_impl.hpp:130:9: required from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::variant<boost::shared_ptr<int> >::move_assigner; VoidPtrCV = void*; T = boost::shared_ptr<int>; typename Visitor::result_type = void; mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/variant/detail/visitation_impl.hpp:173:9: required from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::variant<boost::shared_ptr<int> >::move_assigner; VoidPtrCV = void*; T = boost::shared_ptr<int>; NoBackupFlag = boost::variant<boost::shared_ptr<int> >::has_fallback_type_; typename Visitor::result_type = void]’
/usr/local/include/boost/variant/detail/visitation_impl.hpp:260:1: required from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>; step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<1l>, boost::shared_ptr<int>, boost::mpl::l_end> >, boost::mpl::l_iter<boost::mpl::l_end> >; Visitor = boost::variant<boost::shared_ptr<int> >::move_assigner; VoidPtrCV = void*; NoBackupFlag = boost::variant<boost::shared_ptr<int> >::has_fallback_type_; typename Visitor::result_type = void; mpl_::false_ = mpl_::bool_<false>]’
/usr/local/include/boost/variant/variant.hpp:2326:13: required from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::variant<boost::shared_ptr<int> >::move_assigner; VoidPtrCV = void*; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename Visitor::result_type = void]’
/usr/local/include/boost/variant/variant.hpp:2337:13: required from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::variant<boost::shared_ptr<int> >::move_assigner; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; typename Visitor::result_type = void]’
/usr/local/include/boost/variant/variant.hpp:2109:13: required from ‘void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant_assign(boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>&&) [with T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> = boost::variant<boost::shared_ptr<int> >]’
/usr/local/include/boost/variant/variant.hpp:2130:13: required from ‘void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::assign(const T&) [with T = boost::shared_ptr<int>; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]’
/usr/local/include/boost/variant/variant.hpp:2168:9: required from ‘boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>& boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::operator=(const T&) [with T = boost::shared_ptr<int>; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19> = boost::variant<boost::shared_ptr<int> >]’
vartest.cpp:7:9: required from here
/usr/local/include/boost/variant/variant.hpp:2058:13: error: no matching function for call to ‘boost::variant<boost::shared_ptr<int> >::move_assigner::assign_impl(boost::shared_ptr<int>&, nothrow_copy, nothrow_move_constructor, boost::variant<boost::shared_ptr<int> >::has_fallback_type_)’
/usr/local/include/boost/variant/variant.hpp:2058:13: note: candidates are:
/usr/local/include/boost/variant/variant.hpp:1959:14: note: template<class RhsT, class B1, class B2> void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::move_assigner::assign_impl(RhsT&, mpl_::true_, mpl_::false_, B2) [with RhsT = RhsT; B1 = B1; B2 = B2; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
/usr/local/include/boost/variant/variant.hpp:1959:14: note: template argument deduction/substitution failed:
/usr/local/include/boost/variant/variant.hpp:2058:13: note: couldn't deduce template parameter ‘B1’
/usr/local/include/boost/variant/variant.hpp:1978:14: note: template<class RhsT, class B> void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::move_assigner::assign_impl(RhsT&, mpl_::true_, mpl_::true_, B) [with RhsT = RhsT; B = B; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
/usr/local/include/boost/variant/variant.hpp:1978:14: note: template argument deduction/substitution failed:
/usr/local/include/boost/variant/variant.hpp:2058:13: note: cannot convert ‘nothrow_move_constructor()’ (type ‘nothrow_move_constructor {aka boost::integral_constant<bool, false>}’) to type ‘mpl_::true_ {aka mpl_::bool_<true>}’
/usr/local/include/boost/variant/variant.hpp:1997:14: note: template<class RhsT> void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::move_assigner::assign_impl(RhsT&, mpl_::false_, mpl_::false_, mpl_::true_) [with RhsT = RhsT; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
/usr/local/include/boost/variant/variant.hpp:1997:14: note: template argument deduction/substitution failed:
/usr/local/include/boost/variant/variant.hpp:2058:13: note: cannot convert ‘nothrow_copy()’ (type ‘nothrow_copy {aka mpl_::bool_<true>}’) to type ‘mpl_::false_ {aka mpl_::bool_<false>}’
/usr/local/include/boost/variant/variant.hpp:2033:14: note: template<class RhsT> void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::move_assigner::assign_impl(const RhsT&, mpl_::false_, mpl_::false_, mpl_::false_) [with RhsT = RhsT; T0_ = boost::shared_ptr<int>; T1 = boost::detail::variant::void_; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
/usr/local/include/boost/variant/variant.hpp:2033:14: note: template argument deduction/substitution failed:
/usr/local/include/boost/variant/variant.hpp:2058:13: note: cannot convert ‘nothrow_copy()’ (type ‘nothrow_copy {aka mpl_::bool_<true>}’) to type ‘mpl_::false_ {aka mpl_::bool_<false>}’

How to implement a boost::variant derived-class?

I have tried for hours to code a class deriving from boost::variant. But I do not understand what is the problem (I do not understand what the compilation error means).
What are the rules to implement a clean boost::variant derived-class?
#include <boost/variant.hpp>
class MyVariant : public boost::variant<char,bool>
{
public:
MyVariant () : boost::variant<char,bool>( ) {}
template <typename T>
MyVariant( T& v) : boost::variant<char,bool>(v) {}
template <typename T>
MyVariant(const T& v) : boost::variant<char,bool>(v) {}
};
int main ()
{
MyVariant a;
MyVariant b = a; //compilation error
// MyVariant c = MyVariant();
// MyVariant d (true);
// MyVariant e ('E');
}
Why do I want to use inheritance? (EDIT to give more details to #zaufi)
I want an empty state
I want to accept const char* as string
I want to accept int as long
I want to give enum types
For instance, in pseudo C++ code, my hopes:
class MyVariant : public boost::variant<char,bool,long,std::string>
{
typedef boost::variant<char,bool,long,std::string> super;
public:
// I know here I should specialize templeted constructors
// but I is more clear like that, isn't it?
MyVariant() : super('e') {} //empty -> char
MyVariant(char c) : super(std::string(1,c)){} //char -> string
MyVariant(const char* s) : super(std::string(s) ) {} //char* -> string
MyVariant(int v) : super(long (v) ) {} //TODO boundaries
/* other constructors ... */
enum Type
{
NONE, //my empty state = char type
BOOL,
LONG,
STRING
};
Type type() const { return (Type) which(); }
};
The basic snippet code (on top of the question) has been tested on different platforms
boost v1.33 + GCC 4.1 (Linux)
boost v1.52 + GCC 4.7 (MinGW)
boost v1.52 + Visual C++ 2010 (v10)
Below my errors for the two versions of GCC
(I can remove one of the both if it bothers someone...)
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ myVariant.cpp
/usr/include/boost/variant/variant.hpp: In constructor 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(T&) [with T = MyVariant, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]':
myVariant.cpp:10: instantiated from 'MyVariant::MyVariant(T&) [with T = MyVariant]'
myVariant.cpp:19: instantiated from here
/usr/include/boost/variant/variant.hpp:1348: error: call of overloaded 'convert_construct(MyVariant&, long int)' is ambiguous
/usr/include/boost/variant/variant.hpp:1262: note: candidates are: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&, int, mpl_::false_) [with T = MyVariant, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
/usr/include/boost/variant/variant.hpp:1321: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char, U1 = bool, U2 = boost::detail::variant::void_, U3 = boost::detail::variant::void_, U4 = boost::detail::variant::void_, U5 = boost::detail::variant::void_, U6 = boost::detail::variant::void_, U7 = boost::detail::variant::void_, U8 = boost::detail::variant::void_, U9 = boost::detail::variant::void_, U10 = boost::detail::variant::void_, U11 = boost::detail::variant::void_, U12 = boost::detail::variant::void_, U13 = boost::detail::variant::void_, U14 = boost::detail::variant::void_, U15 = boost::detail::variant::void_, U16 = boost::detail::variant::void_, U17 = boost::detail::variant::void_, U18 = boost::detail::variant::void_, U19 = boost::detail::variant::void_, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
/usr/include/boost/variant/variant.hpp:1330: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char, U1 = bool, U2 = boost::detail::variant::void_, U3 = boost::detail::variant::void_, U4 = boost::detail::variant::void_, U5 = boost::detail::variant::void_, U6 = boost::detail::variant::void_, U7 = boost::detail::variant::void_, U8 = boost::detail::variant::void_, U9 = boost::detail::variant::void_, U10 = boost::detail::variant::void_, U11 = boost::detail::variant::void_, U12 = boost::detail::variant::void_, U13 = boost::detail::variant::void_, U14 = boost::detail::variant::void_, U15 = boost::detail::variant::void_, U16 = boost::detail::variant::void_, U17 = boost::detail::variant::void_, U18 = boost::detail::variant::void_, U19 = boost::detail::variant::void_, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
$ g++ --version
g++.exe (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ myVariant.cpp -I /c/.../include/
In file included from c:/.../include/boost/variant.hpp:17:0,
from myVariant.cpp:1:
c:/.../include/boost/variant/variant.hpp: In instantiation of 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(T&) [with T = MyVariant; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]':
myVariant.cpp:9:66: required from 'MyVariant::MyVariant(T&) [with T = MyVariant]'
myVariant.cpp:18:25: required from here
c:/.../include/boost/variant/variant.hpp:1406:9: error: call of overloaded convert_construct(MyVariant&, long int)' is ambiguous
c:/.../include/boost/variant/variant.hpp:1406:9: note: candidates are:
c:/.../include/boost/variant/variant.hpp:1316:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&, int, mpl_::false_) [with T = MyVariant; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; mpl_::false_ = mpl_::bool_<false>]
c:/.../include/boost/variant/variant.hpp:1376:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char; U1 = bool; U2 = boost::detail::variant::void_; U3 = boost::detail::variant::void_; U4 = boost::detail::variant::void_; U5 = boost::detail::variant::void_; U6 = boost::detail::variant::void_; U7 = boost::detail::variant::void_; U8 = boost::detail::variant::void_; U9 = boost::detail::variant::void_; U10 = boost::detail::variant::void_; U11 = boost::detail::variant::void_; U12 = boost::detail::variant::void_; U13 = boost::detail::variant::void_; U14 = boost::detail::variant::void_; U15 = boost::detail::variant::void_; U16 = boost::detail::variant::void_; U17 = boost::detail::variant::void_; U18 = boost::detail::variant::void_; U19 = boost::detail::variant::void_; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
c:/.../include/boost/variant/variant.hpp:1385:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char; U1 = bool; U2 = boost::detail::variant::void_; U3 = boost::detail::variant::void_; U4 = boost::detail::variant::void_; U5 = boost::detail::variant::void_; U6 = boost::detail::variant::void_; U7 = boost::detail::variant::void_; U8 = boost::detail::variant::void_; U9 = boost::detail::variant::void_; U10 = boost::detail::variant::void_; U11 = boost::detail::variant::void_; U12 = boost::detail::variant::void_; U13 = boost::detail::variant::void_; U14 = boost::detail::variant::void_; U15 = boost::detail::variant::void_; U16 = boost::detail::variant::void_; U17 = boost::detail::variant::void_; U18 = boost::detail::variant::void_; U19 = boost::detail::variant::void_; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
The accepted answer and the other answers do not answer the question. There are good reasons to derive from boost::variant.
you want to add methods into the variant, so that it behaves more polymorphic
you want to keep using boost::apply_visitor(visitor(), variant) without jumping through hoops
Here is a working example of a type MyVariant inheriting from boost::variant. The code requires C++11 to inherit the (complex) constructors of boost::variant.
Edit: Operators such as equal comparison implemented in boost::variant do not automatically work for the derived class. This is a (unintended) consequence of how boost::variant is implemented, it explicitly prevents comparisons to "foreign" types using templates. Operators can be enabled with explicit overloads, as shown in the example.
#include<iostream>
#include<boost/variant.hpp>
struct type_size_visitor : public boost::static_visitor<unsigned> {
template <typename T>
unsigned operator()(const T&) const { return sizeof(T); }
};
template <typename... Types>
class MyVariant : public boost::variant<Types...>
{
using base_type = boost::variant<Types...>;
public:
// inherit constructors
using base_type::base_type;
// add a new method
unsigned type_size() { return boost::apply_visitor(type_size_visitor(), *this); }
/* Inheriting operators from boost::variant does not
work as it normally would. We have to add explicit
overloads for the operators we want to use.
*/
bool operator==(const MyVariant& rhs) const {
// cast rhs to base and delegate to operator in base
return base_type::operator==(static_cast<const base_type&>(rhs));
}
};
int main() {
MyVariant<std::string, char> v;
v = 1;
std::cout << v.type_size() << " " << sizeof(char) << std::endl;
v = std::string("foo");
std::cout << v.type_size() << " " << sizeof(std::string) << std::endl;
// comparison operators need workaround shown above
MyVariant<std::string, char> a, b;
a = 1; b = 1;
assert(a == b);
}
I want an empty state
boost::variant<boost::blank, bool, long, std::string>
There. That was much easier. No need for messy inheritance.
I want to give enum types
enum Type
{
NONE,
BOOL,
LONG,
STRING
};
struct GetType : public boost::static_visitor<Type>
{
Type operator()(boost::blank) {return NONE;}
Type operator()(bool) {return BOOL;}
Type operator()(long) {return LONG;}
Type operator()(const std::string&) {return STRING;}
};
//Get the type
Type t = boost::apply_visitor(GetType(), theData);
That was easy too. Plus, if you add a new type to the variant, your code will break if you don't update GetType to match.
The other two criteria require you to use a class, but you don't need inheritance. You need containment.
typedef boost::variant<boost::blank, std::string, long> VarType;
class MyVariant
{
public:
//Default construction will initialize with boost::blank.
MyVariant(char c) : m_var(std::string(1,c)) {}
MyVariant(const char* s) : m_var(std::string(s)) {}
MyVariant(int v) : m_var(long(v)) {}
MyVariant(long v) : m_var(long(v)) {}
VarType &operator *() {return m_var;}
const VarType &operator *() const {return m_var;}
private:
VarType m_var;
};
...
Type t = boost::apply_visitor(GetType(), *theData);
Finally my implementation based on Nicol Bolas's answer:
Variant.h
class Variant
{
public:
Variant() : v_(boost::blank()) {}
Variant(bool v) : v_(v) {}
Variant(long v) : v_(v) {}
Variant(int v) : v_(long(v)) {}
Variant(double v) : v_(v) {}
Variant(const std::string& s) : v_(s) {}
Variant(const char* s) : v_(std::string(s)) {}
typedef boost::variant <boost::blank, bool,
long, double, std::string> bstvar;
enum Type {
NONE, BOOL, // above underlying types
LONG, DOUBLE, STRING // and enum must be consistent:
}; // (order must be same)
operator bstvar& () { return v_; }
operator const bstvar& () const { return v_; }
bstvar & operator*() { return v_; }
bstvar const& operator*() const { return v_; }
bool empty () const { return type() == NONE; }
bool toBool () const { return boost::get<bool > (v_); }
long toLong () const { return boost::get<long > (v_); }
double toDouble () const { return boost::get<double> (v_); }
std::string const& toStr () const { return boost::get<std::string> (v_); }
std::string & toStr () { return boost::get<std::string> (v_); }
inline Type type () const { return (Type) v_.which(); }
static Type type (const std::string&);
static std::string type (Type t);
private: bstvar v_; // Data
};
Variant.cpp
#include "Variant.h"
#include <sstream>
#include <algorithm> //std::transform
Variant::Type Variant::type (const std::string& str)
{
std::string lower = str;
std::transform (lower.begin(), lower.end(), lower.begin(), ::tolower);
if (lower == "bool") return BOOL;
if (lower == "long") return LONG;
if (lower == "double") return DOUBLE;
if (lower == "string") return STRING;
else return NONE;
}
std::string Variant::type (Type t)
{
switch (t)
{
case NONE: return "none";
case BOOL: return "bool";
case LONG: return "long";
case DOUBLE: return "double";
case STRING: return "string";
default:
;//see below
}
std::ostringstream oss;
oss <<"Unexpected type="<< t;
return oss.str();
}

best way to do variant visitation with lambdas

I want to inline visitation of variant types with lambdas. At the moment i have the following code:
struct Foo {
boost::variant< boost::blank , int , string , vector< int > > var;
template <typename T, typename IL , typename SL , typename VL>
void ApplyOptionals( T& ref, IL&& intOption , SL&& stringOption , VL&& vectorOption ) {
if (var.which() == 1) {
intOption( ref , boost::get< int >(var) );
} else if (var.which() ==2) {
stringOption( ref , boost::get< string>(var) );
} else if (var.which() == 3) {
vectorOption( ref , boost::get< vector< int > >(var) );
}
};
};
// ...
myFooV.ApplyOptionals(
obj,
[](Obj& o, int v) -> void { cout << "int: " << v << endl; o.value = v; },
[](Obj& o, string v) -> void{ cout << "string: " << v << endl; o.name = v; },
[](Obj& o, vector< int >& v) -> void{ v.push_back(257); cout << " vector.. has elements: " << v.size() << endl; o.ids = v; }
);
However the main drawback of this approach is that it depends on the order of variant type parameters and doesn't detect at compile-time unhandled types like boost::static_visitor would do
Can i get the best of both approaches?
Working on the excellent answer from RMartinho, i'm trying to work out this error, it seems that variant thinks the operator() calls are amibiguous (i'm using g++ 4.5.1, it's like it couldn't see the lambda operators.
looking at this question request for member `...' is ambiguous in g++, it seems that c++ doesn't like multiple inheritance as a way to provide multiple overloads (even if the calls are completely non-ambiguous because of different signature)
#include <iostream>
#include <string>
#include <vector>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant< boost::blank , int , string , vector< int > > var_t;
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor : public boost::static_visitor<ReturnType>, public Lambdas... {
lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... { }
};
template <typename ReturnType>
struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
lambda_visitor() {}
};
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
return { lambdas... };
// you can use the following instead if your compiler doesn't
// support list-initialization yet
// return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
}
int main() {
vector< int > vit;
vit.push_back(7);
var_t myFooV = vit;
auto visitor = make_lambda_visitor<void>(
[](int v) -> void { cout << "int: " << v << endl; },
[](string& v) -> void{ cout << "string: " << v << endl; },
[](vector< int >& v) -> void{ v.push_back(27); boost::get< vector< int > >(myFooV).push_back(34); cout << " vector.. has elements: " << v.size() << endl; }
);
cout << " and for the grand finale.. " << endl;
boost::apply_visitor( visitor , myFooV );
};
This, gives me roughly a bunch of template boost errors, but the distinct part is:
boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
test2.cpp:44:54: error: candidates are: main()::<lambda(std::vector<int>&)>
test2.cpp:43:47: error: main()::<lambda(std::string&)>
test2.cpp:42:55: error: main()::<lambda(int)>
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
This is the whole error, just in case i'm missing some other relevant info:
boost_1_46_0/boost/variant/variant.hpp: In member function ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = std::vector<int>, Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, boost::detail::variant::invoke_visitor<Visitor>::result_type = void]’:
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:130:9: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_<true>]’
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:173:9: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::has_fallback_type_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/detail/visitation_impl.hpp:260:1: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<4l>, boost::blank, boost::mpl::l_item<mpl_::long_<3l>, int, boost::mpl::l_item<mpl_::long_<2l>, std::basic_string<char>, boost::mpl::l_item<mpl_::long_<1l>, std::vector<int>, boost::mpl::l_end> > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_<false>]’
boost_1_46_0/boost/variant/variant.hpp:1776:13: instantiated from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/variant.hpp:1787:13: instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/variant.hpp:1810:52: instantiated from ‘typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::apply_visitor(Visitor&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’
boost_1_46_0/boost/variant/detail/apply_visitor_unary.hpp:60:43: instantiated from ‘typename Visitor::result_type boost::apply_visitor(Visitor&, Visitable&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, Visitable = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >, typename Visitor::result_type = void]’
test2.cpp:49:40: instantiated from here
boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous
test2.cpp:44:54: error: candidates are: main()::<lambda(std::vector<int>&)>
test2.cpp:43:47: error: main()::<lambda(std::string&)>
test2.cpp:42:55: error: main()::<lambda(int)>
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
conclusion:
I want to add the final version of this utility, including tests:
lambda_visitor.h
#include <boost/variant.hpp>
namespace Variant {
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor;
template <typename ReturnType, typename Lambda1, typename... Lambdas>
struct lambda_visitor< ReturnType, Lambda1, Lambdas...>
: public lambda_visitor<ReturnType, Lambdas...>, public Lambda1 {
using Lambda1::operator();
using lambda_visitor< ReturnType, Lambdas...>::operator();
typedef ReturnType ReturnType_t;
lambda_visitor(Lambda1 l1, Lambdas... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
}
lambda_visitor(Lambda1 && l1, Lambdas && ... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
}
};
template <typename ReturnType, typename Lambda1>
struct lambda_visitor<ReturnType, Lambda1>
: public boost::static_visitor<ReturnType>, public Lambda1 {
using Lambda1::operator();
typedef ReturnType ReturnType_t;
lambda_visitor(Lambda1 l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
}
lambda_visitor(Lambda1 && l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
}
};
template <typename ReturnType>
struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
typedef ReturnType ReturnType_t;
lambda_visitor() : boost::static_visitor<ReturnType > () {
}
};
template <typename ReturnType>
struct default_blank_visitor {
typedef ReturnType ReturnType_t;
inline ReturnType operator() (const boost::blank&) const {
return (ReturnType) 0;
};
};
template<>
struct default_blank_visitor<void> {
typedef void ReturnType_t;
inline void operator() (const boost::blank&) const {};
};
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
return
{
default_blank_visitor<ReturnType > (), lambdas...
};
// you can use the following instead if your compiler doesn't
// support list-initialization yet
//return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
};
/*
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas && ... lambdas) {
return
{
default_blank_visitor<ReturnType > (), lambdas...
};
// you can use the following instead if your compiler doesn't
// support list-initialization yet
//return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
};*/
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor_override_blank(Lambdas... lambdas) {
return
{
lambdas...
};
// you can use the following instead if your compiler doesn't
// support list-initialization yet
//return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
}
namespace basic_usage
{
struct Test
{
typedef boost::variant< boost::blank , int , double > variant_t;
void run()
{
variant_t a, b, c;
a = 42;
b = 3.14159265;
auto visitor = Variant::make_lambda_visitor<int>( [](int v) -> int { return v+1; } , [](double v) -> int { return (int)v*2; } );
int result = boost::apply_visitor(visitor, a);
HAssertMsg( result == (42 + 1) , "unexpected");
result = boost::apply_visitor( visitor , b);
HAssertMsg( result == 6 , "unexpected");
auto blankVisitor = Variant::make_lambda_visitor_override_blank<int>(
[](int v) -> int { return -1; }
, [](double v) -> int { return -1; }
, [](boost::blank ) -> int { return 0;} );
result = boost::apply_visitor( blankVisitor , c);
HAssertMsg( result == 0 , "unexpected");
//same as previous case, but using lambda coalescing :-)
auto blankVisitor2 = Variant::make_lambda_visitor_override_blank<int>(
[](boost::variant< int , double >& v) -> int { return -1; }
, [](boost::blank ) -> int { return 0;} );
result = boost::apply_visitor( blankVisitor2 , c);
HAssertMsg( result == 0 , "unexpected");
result = boost::apply_visitor( blankVisitor2 , a);
HAssertMsg( result == -1 , "unexpected");
result = boost::apply_visitor( blankVisitor2 , b);
HAssertMsg( result == -1 , "unexpected");
}
};
}
};
You could use variadic templates to take the lambdas, and build a variant visitor using inheritance. That would retain the compile time checks.
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor : public static_visitor<ReturnType>, public Lambdas... {
lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... {}
};
And a little helper function to use argument type deduction (required for lambdas):
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
return { lambdas... };
// you can use the following instead if your compiler doesn't
// support list-initialization yet
// return lambda_visitor<ReturnType, Lambdas...>(lambdas...);
}
Now you can make visitors like this:
auto visitor = make_lambda_visitor<int>([](int) { return 42; },
[](std::string) { return 17; },
[](std::vector<int>) { return 23; });
Note: due to a detail of the overload resolution process that I wasn't aware of, this elegant solution causes weird ambiguity errors :(
See the follow-up question for the fix.