Boost variant has a function called make_variant_over
that takes an MPL sequence (for example list<A, B, C>
) and produces a variant from those types.
However if one looks carefully the type generated is never a simple variant<A, B, C>
.
For example in this code,
#include<boost/variant.hpp>
int main(){
using List = boost::mpl::list<double, int>;
using Variant = boost::make_variant_over<List>::type;
}
Variant
is boost::variant<boost::detail::variant::over_sequence<boost::mpl::list<double, int, mpl_::na, ...> >>
.
It looks like it can be used interchangeability with boost::variant<double, int>
, but it is not the same type. At best that can generate confusion when reading compiler errors and at worst it can make difficult to implement certain functions that rely on the exact type of the argument.
Is there a way to force a simplification in the produced variant type?
Got it, using boost::mpl::fold
.
One has to be careful with the recursion because empty template variants cannot be instantiated.
It can be done, but we are probably not doing the compiler any favor because boost::variant<T1, T2,...>
is probably still implemented in terms of boost::variant<...variant::over_sequence<T1, T2,...>>
.
The real power can be that one can use the simplified type construction to make the variants type unique.
namespace detail{
template <typename TList, typename T> struct ExtendTList;
template<typename T>
struct ExtendTList<boost::variant<void>, T>{
using type = boost::variant<T>;
};
template<typename T, typename... Ts>
struct ExtendTList<boost::variant<Ts...>, T>{
using type = boost::variant<Ts..., T>;
};
}
template<class Seq>
using make_simple_variant_over = typename boost::mpl::fold<
typename boost::mpl::fold<
Seq,
boost::mpl::set<>,
boost::mpl::insert<boost::mpl::_1, boost::mpl::_2>
>::type,
boost::variant<void>,
detail::ExtendTList<boost::mpl::_1, boost::mpl::_2>
>;
...
using variant_type = make_simple_variant_over<boost::mpl::vector<int, int, long>>::type;
variant_type
is now exactly boost::variant<int, long>
.
(and it is not boost::variant<boost::detail::variant::over_sequence<boost::mpl::list<int, long, mpl_::na, ...> >>
nor boost::variant<boost::detail::variant::over_sequence<boost::mpl::list<int, int, long, mpl_::na, ...> >>