Joe
Joe

Reputation: 6757

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&}'

Upvotes: 2

Views: 754

Answers (1)

ecatmur
ecatmur

Reputation: 157344

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

Upvotes: 4

Related Questions