c++visual-c++template-meta-programmingboost-mpltag-dispatching

Tag dispatching with transformed `boost::mpl::vector`s


I am trying to tag-dispatch into a function with a reversed copy of a boost::mpl::vector:

using InitOrder = boost::mpl::vector<
    struct Foo,
    struct Bar,
    struct Baz
>;

template <class... Stuff>
void initialize(boost::mpl::vector<Stuff...>) {
    // Initialize in-order
}

template <class... Stuff>
void destroy(boost::mpl::vector<Stuff...>) {
    // Exit in-order
}

void initializeAll() {
    initialize(InitOrder{});
}

void destroyAll() {
    destroy(typename boost::mpl::reverse<InitOrder>::type{});
}

Coliru demo

As you can see, the goal is to have two processes in initialize and destroy that have access to the Stuff pack. However, as answered here, boost::mpl::reverse<InitOrder>::type is actually not a boost::mpl::vector, and the dispatching fails:

main.cpp:27:2: error: no matching function for call to 'destroy'
        destroy(typename boost::mpl::reverse::type{});
        ^~~~~~~
main.cpp:18:6: note: candidate template ignored: could not match 'vector' against 'v_item'
void destroy(boost::mpl::vector) {
     ^

I can ditch Boost.MPL if needed, provided the alternative is standard or Boost. I'm using MSVC 14.1.


Solution

  • Is Boost.MPL inherently incompatible with variadic templates?

    Basically. MPL predates C++11, so to use MPL, you need to use their algorithms - so their Sequence concept with their Iterators, etc. There's almost certainly a really short, clever way to do this, but I can only ever find those out with guess and check.


    At least, if all you need to do is reverse, this is straightforward to implement in C++11:

    template <typename...> struct typelist { };
    
    template <typename TL, typeanme R>
    struct reverse_impl;
    
    template <typename T, typename... Ts, typename... Us>
    struct reverse_impl<typelist<T, Ts...>, typelist<Us...>>
    : reverse_impl<typelist<Ts...>, typelist<Us..., T>>
    { };
    
    template <typename... Us>
    struct reverse_impl<typelist<>, typelist<Us...>>
    {
        using type = typelist<Us...>;
    };
    
    template <typename TL>
    using reverse = typename reverse_impl<TL, typelist<>>::type;
    

    So given:

    using InitOrder = typelist<struct Foo, struct Bar, struct Baz>;
    

    Then reverse<InitOrder> would be typelist<struct Baz, struct Bar, struct Foo>, and so would be usable in the way you'd want.