Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending boost variant with an MPL list

I'm trying to provide a program a way to add new objects to a variant in a library but I'm encountering some cryptic errors.

#include <boost/mpl/copy.hpp>
#include <boost/mpl/joint_view.hpp>
#include <boost/mpl/list.hpp>
#include <boost/variant/variant.hpp>

struct InternalType1 {};
struct InternalType2 {};

template <typename LocalTypes>
struct Foo
{
  typedef boost::mpl::list<
    InternalType1,
    InternalType2
  > Types;

  typename boost::make_variant_over<
    typename boost::mpl::joint_view<
      Types,
      LocalTypes
    >::type
  >::type container_;

  // typename boost::make_variant_over<
  //   typename boost::mpl::copy<
  //     LocalTypes,
  //     boost::mpl::back_inserter<Types>
  //   >::type
  // >::type container_;
};

struct LocalType1 {};
struct LocalType2 {};

int main()
{
  typedef boost::mpl::list<
    LocalType1,
    LocalType2
  > Types;

  Foo<Types> foo;
}

By using a mpl::joint_view (which I assume if the most efficient way of achieving this), I get the following error:

/usr/local/include/boost/mpl/clear.hpp:29:7: error: implicit instantiation of undefined template

By uncommenting the other attempt, using mpl::copy, and replacing it with the original, then the error changes:

/usr/local/include/boost/mpl/aux_/push_back_impl.hpp:40:9: error: no matching function for call to 'assertion_failed'

Which, interestingly, has the following comment:

// should be instantiated only in the context of 'has_push_back_impl';
// if you've got an assert here, you are requesting a 'push_back' 
// specialization that doesn't exist.

Neither of these errors make any sense to me as, w/r/t the first, I don't see which templates are not complete and for the second, which push_back specialization I'm not using?

like image 771
Sam Kellett Avatar asked Dec 20 '14 14:12

Sam Kellett


1 Answers

The problem is that boost::mpl::clear<> is not implemented for a joint_view... hence the huge compiler dump terminating with:

/usr/local/include/boost/mpl/clear.hpp:29:7: error: implicit instantiation of undefined template 'boost::mpl::clear_impl<boost::mpl::aux::joint_view_tag>::apply<boost::mpl::joint_view<boost::mpl::list<InternalType1, InternalType2, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::mpl::list<LocalType1, LocalType2, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na> > >'

(I don't know how to format that properly)

This could be just an oversight in the library, or it may just not be clear which empty Sequence type should be returned in this case. If you want to use a joint_view, you'll have to provide a specialization of clear_impl somewhere:

namespace boost { namespace mpl {
   template <>
   struct clear_impl<aux::joint_view_tag>
   {
       template <typename JV>
       struct apply {
           typedef list<> type; // since you're using list I figured
                                // I would too.
       };
   };
} }

With that, your code compiles for me on both gcc and clang.

Alternatively, if adding stuff into namespace boost::mpl strikes you as a little shady but you still want to stick with lists, you can just use insert_range:

typename boost::make_variant_over<
    typename boost::mpl::insert_range<
        Types,
        typename boost::mpl::end<Types>::type,
        LocalTypes
    >::type
>::type container_;
like image 134
Barry Avatar answered Nov 07 '22 01:11

Barry