Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate over C++ variadic template

I have the following:

template<typename FIRST, typename SECOND>
Sender *createSenderChain() {
    return new FIRST(new SECOND());
}

Is it possible to make the template variadic:

template<typename FIRST, typename ...Args>
Sender *createSenderChain() {
    return new FIRST(new SECOND(new THIRD(new ...))  <-- This is the pattern I want, 
                                                         but how should it be done 
                                                         using the args list?
}
like image 590
user2479653 Avatar asked Apr 04 '17 10:04

user2479653


2 Answers

You can use recursion for this!

Guessing at your definition of Sender:

struct Sender { ~Sender() {} };

struct A : Sender { A(Sender* = nullptr) {} };
struct B : Sender { B(Sender* = nullptr) {} };
struct C : Sender { C(Sender* = nullptr) {} };


// Base case
template <typename T>
Sender* createSenderChain()
{
    return new T();
}

// Recursive case
template <typename T1, typename T2, typename ...Ts>
Sender* createSenderChain()
{
    return new T1(createSenderChain<T2, Ts...>());
}

int main()
{
    auto ptr = createSenderChain<A, B, C>();
}

(live demo)

like image 162
Lightness Races in Orbit Avatar answered Sep 28 '22 18:09

Lightness Races in Orbit


You can call the same variadic template function with different template arguments:

template<typename FIRST, typename SECOND, typename ...Args>
Sender* createSenderChain() {
    return new typename FIRST(createSenderChain<SECOND, Args...>());
}

template<typename FIRST>
Sender* createSenderChain() {
    return new typename FIRST();
}

In the first function we explicitly state not only typename FIRST, but also typename SECOND to avoid matching this implementation to createSenderChain<T> calls, since the variadic part may be matched with empty list of types.

like image 25
alexeykuzmin0 Avatar answered Sep 28 '22 18:09

alexeykuzmin0