BiagioF
BiagioF

Reputation: 9715

Empty Pack Variadic Template

Let's say I have some action to perform, at compile time:

enum class Action {A, B};

Now I write a template variadic function which performs a possible combination of action in sequence:

template <Action a>
void applyAction();

template <typename = void>
void applyActions() {}

template <Action a, Action... as>
void applyActions() {
  applyAction<a>();
  applyActions<as...>();
}

This code is fine. Indeed:

void foo() {
  applyActions<Action::A, Action::B>();
}

correctly generates:

call void applyAction<(Action)0>()
call void applyAction<(Action)1>()

GodBolt Example Here


In order to achieve the expansion pack termination, I had to declare the dummy function:

template <typename = void> void applyActions() {}

which is quite "ugly" to me because it gives the possibility to invoke a generic type.

In C++11, Is there a way to declare a variadic function which accepts an empty parameter pack?

Of course, its declaration does not have to bring to call ambiguity with the needed function:

template <Action a, Action... as>
void applyActions();

Something like:

template <Action.. = {}>
void applyActions() {}

Here a not compilable example because of a call ambiguity. But it gives an idea of what I want to achieve.

Upvotes: 3

Views: 1862

Answers (2)

rmawatson
rmawatson

Reputation: 1935

An alternative way to structure it so you can remove the 'ugly' default is the following, which also removes the recursion and would work with an empty actions parameter pack,

#include <iostream>
using namespace std;

enum class Action {A, B};

template <Action a>
void applyAction()
{
   std::cout << "Action  " << (int)a << std::endl;
}

template <Action... as>
void applyActions() {
    using do_= int[];
    (void)do_{0, ( 
       applyAction<as>()
    ,0)...}; 
}

void foo() {
  applyActions<Action::A, Action::B>();
}

void bar() {
  applyActions<Action::B, Action::A>();
}


int main() {
    foo();
    bar();
    return 0;
}

Demo

As pointed out by HolyBlackCat, in c++17 you could just use a fold expression,

template <Action... as>
void applyActions() {

       (applyAction<as>(), ...);
}

Upvotes: 5

max66
max66

Reputation: 66200

In C++11, Is there a way to declare a variadic function which accepts an empty parameter pack?

Yes: there is and it's trivial

template <Action...>
void applyActions()

The problem is that, in your case, collide with the function that accept with one or more elements

template <Action a, Action... as>
void applyActions()

and when you call applyActions<as...>(); with a not empty as... pack, both template match.

The use of a template function with the same name but a different genre of argument (and a default value)

template <typename = void>
void applyActions() {}

it's (IMHO) an extremely smart, cheap and elegant way to solve the termination problem.

Upvotes: 1

Related Questions