Extending boost variant with an MPL list
Asked Answered
S

1

6

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?

Speculation answered 20/12, 2014 at 14:48 Comment(4)
The second one is pretty easy to understand, mpl::list can't be used with push_back. You could use boost::mpl::front_inserter<Types> or simply use a mpl::vector in your Types typedef.Anguished
Aaaah, yeah that's it. Thanks! I'll leave the question open due to the joint_view solution probably being the better or the two to do in production.Speculation
I don't see a better way unless you intend to modify make_variant_over. mpl::copy from mpl::vectors is the way if you ask meUlick
So is the joint_view not a feasible thing to do here? It says in the documentation for make_variant_over that it requires an MPL Sequence. And then the joint_view docs state that joint_view is a Forward Sequence. So these two should be compatible, no?Speculation
D
2

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_;
Dickdicken answered 30/12, 2014 at 14:16 Comment(2)
That seems to be it, thanks! I guess, taking this into context, an mpl::copy and mpl::vector really does sound like the best choice. Like you said, an empty mpl::joint_view doesn't really make any sense...Speculation
@SamKellett Can actually use the same insert_range metafunction with vector too. Either way, you end up with the same thing.Dickdicken

© 2022 - 2024 — McMap. All rights reserved.