3

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?

alfC
  • 14,261
  • 4
  • 67
  • 118
  • This seems to boil down to the philosophy of MPL, in which the results of metaprograms do not simplify but functionally behave like the simplified result. See http://stackoverflow.com/questions/28585599/how-to-obtain-standard-mpl-sequence-after-fold – alfC Mar 05 '17 at 00:59

1 Answers1

0

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, ...> >>

alfC
  • 14,261
  • 4
  • 67
  • 118