Search code examples
c++c++11template-meta-programmingboost-mpl

How do I merge two mpl maps producing a new map?


However I tweek the following code, there seems to be a point I am missing. It will not compile. I have two maps int -> int. I want to produce a third int -> int map containing all the key-value pairs from the two originals. (VS2013) Anyone?

#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/has_key.hpp>

typedef boost::mpl::map <
    boost::mpl::pair < boost::mpl::int_<7>, boost::mpl::int_<59>  >
>::type Original1;

typedef boost::mpl::map <
    boost::mpl::pair < boost::mpl::int_<11>, boost::mpl::int_<61>  >
>::type Original2;

typedef boost::mpl::copy <
    Original1,
    boost::mpl::back_inserter < Original2 >
>::type Merged;

BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));

int _tmain(int argc, _TCHAR* argv[])
{

    const int i = boost::mpl::at<Merged, boost::mpl::int_<7> >::type::value;

    return 0;
}

Solution

  • There are two problems with your code. The simple one is here:

    BOOST_MPL_ASSERT((boost::mpl::has_key<Merged, 7>));
    

    Keys are types, 7 is not a type. You want to check for the key mpl::int_<7>.

    The second is here:

    typedef boost::mpl::copy <
        Original1,
        boost::mpl::back_inserter < Original2 > // <==
    >::type Merged;
    

    mpl::back_inserter is the metaprogramming equivalent of std::back_inserter, which creates an OutputIterator which outputs via push_back(). Similarly, back_inserter requires a "Back Extensible Sequence" because it uses mpl::push_back. mpl::map isn't a Back Extensible Sequence. If you look at its reference, there's no push_back, only insert. So you need to do that:

    using Merged =
        mpl::copy<
            Original1,
            mpl::inserter<Original2, mpl::insert<mpl::_1, mpl::_2>> // <==
        >::type;
    

    I don't quite understand what mpl::quote is doing, but it seems broken (er, actually, mpl::insert takes 3 arguments and mpl::quote3 doesn't allow for defaulting the last arguments). If you write:

    template <template <class... > class F>
    struct quote {
        template <class... Args>
        struct apply {
            using type = typename F<Args...>::type;
        };
    };
    

    then you could have just written:

    mpl::inserter<Original2, quote<mpl::insert>>