Search code examples
c++c++14variadic-templates

build and pass list of types to variadic templates


I'm very new to meta-programming and I'm experimenting with some examples.

I've designed a variadic template class as follows:

template <typename TA, typename... TB>
class A
[...]

This could be instantiated simply by passing different types like

A<Class1, Class2, Class3> * a = &(A<Class1, Class2, Class3>::instance());

where the pack TB only contains Class2 and Class3. Now, what I would like to achieve is to define in my header file a list of default types and build it gradually using #ifdef definitions. I'll make an example

// concept of list of types
template<class... Ts>
struct typelist{};

// concatenating two typelists
template<class... Ts, class... Us>
auto concat(typelist<Ts...>, typelist<Us...>) -> typelist<Ts..., Us...>;

static typelist<> defaultTypelist;

#ifdef MACRO1
defaultTypelist = concat(defaultTypelist, typelist<Class2>);
// or something like defaultTypelist.push_front(Class2);
#endif
#ifdef MACRO2
defaultTypelist = concat(defaultTypelist, typelist<Class3>);
// or something like defaultTypelist.push_front(Class3);
#endif

By doing that, in my main I would like to instantiate my object as follows:

A<Class1, defaultTypelist> * a = &(A<Class1, defaultTypelist>::instance());

The main problem I see here is that I'm not able to gradually append types to defaultTypelist since it was declared in the beginning at empty template typelist<>. The compiler also returns an error if I try to pass an empty typelist as second parameter. This may be trivial but so far I was not able to solve this, mainly because, as a beginner in meta-programming, compiler errors are not very helpful to me.

For this project, I have to use C++14 and below.


Solution

  • Big fat warning: don't do this.

    The reason I'm saying, it'll change during the code. As you gradually add types, you'll end up defaultTypeList having multiple meanings in different places of the code.

    That said... Can it be done? Of course,

    #define DEFAULT_TYPE_LIST typelist<>()
    
    // ...
    #ifdef MACRO1
    static constexpr auto macro1_prev_dtl = DEFAULT_TYPE_LIST;
    #undef DEFAULT_TYPE_LIST
    #define DEFAULT_TYPE_LIST concat(macro1_prev_dtl, typelist<Class2>())
    #endif
    
    // ...
    #ifdef MACRO2
    static constexpr auto macro2_prev_dtl = DEFAULT_TYPE_LIST;
    #undef DEFAULT_TYPE_LIST
    #define DEFAULT_TYPE_LIST concat(macro2_prev_dtl, typelist<Class3>())
    #endif
    

    ... then use DEFAULT_TYPE_LIST wherever you'd like to access the current state of the list.