将boost::make_recurive_variant与元组一起使用

Using boost::make_recursive_variant with tuple

本文关键字:一起 元组 recurive boost make variant      更新时间:2023-10-16

boost::make_recursive_variant旨在生成递归的变体,而不需要使用标记类型boost::recursive_variant_创建中间类型。对于std::vector<recursive_variant_>,这似乎可以正常工作,但对于std::tuple<int, recursive_variant_>,它会失败。

示例:

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

如果最后一行被取消注释,程序将不再编译。这是一个使用错误吗(如果是,是怎么回事?),还是boost::tuple中的错误或限制?


错误消息(在带有gcc 4.8.1的mingw-w64上):

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:projectstestmain.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:projectstestmain.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:projectstestmain.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&}'

问题是make_recursive_variant不知道可变模板,所以它不知道在std::tuple<..., recursive_variant_>中扩展recursive_variant_

您可以通过将std::tuple更改为std::pair(一个固定的adic模板)来测试这一点,并观察到它运行良好。

作为一种变通方法,您可以教Boost.Variant如何使用以下代码段(位于源文件的顶层)在可变模板中展开:

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

编辑:我已经提交了一个拉取请求:https://github.com/boostorg/variant/pull/2