CRTP + variadic template + extract CRTP subclass parameters

c++, c++11, crtp, templates, variadic-templates

Solution

You could leave the primary template of `CRTPBase` undefined:

template<typename T> class CRTPBase;

And then partially specialize it this way:

template<template<typename, typename...> class TT, 
    typename SENDER, typename... ARGS>
class CRTPBase<TT<SENDER, ARGS...>>
{
    // ...
};

Here is a simple program that shows the type arguments could be retrieved in `CRTPBase`:

#include <tuple>
#include <type_traits>

template<typename T> class CRTPBase;

template<template<typename, typename...> class TT,
    typename SENDER, typename... ARGS>
class CRTPBase<TT<SENDER, ARGS...>>
{
    using type = std::tuple<SENDER, ARGS...>;
};

template<typename SENDER , typename... ARGS>
class event : public CRTPBase<event<SENDER,ARGS...>>
{
    // ...
};

struct X { };

int main()
{
    event<X, int, double> e;

    // This assertion will not fire!
    static_assert(std::is_same<
        decltype(e)::type,
        std::tuple<X, int, double>
        >::value, "!");
}

Here is the corresponding live example.

Problem

Im currently implementing a generic event class. Event handlers have a sender parameter and a variable number of event args. So the declaration of the event class is as bellow: ``` template<typename SENDER , typename... ARGS> class event; ``` To allow certain implementation details, I need a CRTP of the event, like this: ``` template<typename SENDER , typename... ARGS> class event : public CRTPBase<event<SENDER,ARGS...>> { ... }; ``` And the CRTP base needs to know the event parameters. So I have tried with a template template param: ``` template<typename SENDER , template<typename SENDER , typename... ARGS> class EVENT, typename ARGS> class CRTPBase { ... }; ``` But this doesn't work (Im using GCC 4.8.1). So: What is the best way to extract the variadic and non-variadic template parameters of the argument of a CRTP? EDIT: Another way is to provide event parameters directly through the CRTP template (`template<typename EVENT , typename EVENT_SENDER , typename... EVENT_ARGS> class CRTPBase;` ), but I think there is a way to do this directly, without writting the params in a explicit way.

Original source