Search code examples
c++boostboost-fusion

How do I join two or more boost fusion maps?


I want to create an associative sequence from two boost::fusion::map types. The types contained in the one of the maps might exist in another, and if this is the case I want to only end up with a single type with that key in the resulting sequence. That is to say, I want the keys to be unique after the joining.

The conventional join operation appears to allow duplicate keys, so it doesn't seem to be a solution. Does anyone know how I could achieve this?

// Here is what I've got:
using namespace boost::fusion;
map<
  pair<int, int>,
  pair<double, int>> Map1;

map<
  pair<bool, int>,
  pair<double, int>> Map2;

// I want to join Map1 with Map2 such that I have
static_assert(std::is_same<Map3, map<
  pair<int, int>,
  pair<double, int>,
  pair<bool, int>>>::value, "");

Solution

  • You'll probably have to eradicate dupes manually: in full c++14 gear Live On Coliru

    auto r = 
        as_map(
            fold(
                fold(m1, m2, [](auto accum, auto elem) { return erase_key<typename decltype(elem)::first_type>(accum); }),
                m1, 
                [](auto accum, auto elem) { return insert(accum, boost::fusion::end(accum), elem); }
            )); 
    

    That's funky. If you replace it with functors instead of lambdas you'd end up similar to:

    auto r = 
        as_map(
            fold(
                fold(m1, m2, erase_corresponding()), 
                m1, 
                insert_helper()
            ));
    

    A simple implementation Live On Coliru still leans on preliminary c++1y support:

     struct erase_corresponding {
        template<typename T, typename U> 
            auto operator()(T map, U elem) const {
                return boost::fusion::erase_key<typename U::first_type>(map);
            }
    };
    
    struct insert_helper {
        template<typename T, typename U> 
            auto operator()(T map, U elem) const {
                return boost::fusion::insert(map, boost::fusion::end(map), elem);
            }
    };
    

    However, to make it all c++03 proof, you'd need to spell it out with the RESULT_OF (which I leave as an exercise for the reader)