Использование boost::make_recursive_variant с кортежем
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
?
Сообщение об ошибке (на mingw-w64 с 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&}'
1 ответ
Проблема в том, что make_recursive_variant
не знает о вариационных шаблонах, поэтому он не знает, чтобы расширить recursive_variant_
в std::tuple<..., recursive_variant_>
,
Вы можете проверить это, изменив std::tuple
в std::pair
(фиксированный шаблон) и наблюдая, что это работает нормально.
В качестве обходного пути вы можете научить 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