Шаблон пустого пакета Variadic - PullRequest
0 голосов
/ 23 июня 2018

Допустим, у меня есть какое-то действие, которое нужно выполнить во время компиляции:

enum class Action {A, B};

Теперь я пишу шаблонную переменную, которая выполняет возможную комбинацию действий в последовательности:

template <Action a>
void applyAction();

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

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

Этот код в порядке.Действительно:

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

правильно генерирует:

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

Пример GodBolt здесь


Чтобы добиться завершения пакета расширения,Мне пришлось объявить фиктивную функцию:

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

, что для меня довольно "уродливо", поскольку дает возможность вызывать универсальный тип.

В C ++ 11, есть ли способ объявить переменную функцию, которая принимает пустой пакет параметров?

Конечно, ее объявление не должно приводить к неоднозначности вызова с необходимой функцией:

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

Что-то вроде:

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

Здесь не компилируемый пример из-за неоднозначности вызовов.Но это дает представление о том, чего я хочу достичь.

Ответы [ 2 ]

0 голосов
/ 23 июня 2018

Альтернативный способ структурировать его так, чтобы вы могли удалить «некрасивое» значение по умолчанию, заключается в следующем, который также удаляет рекурсию и будет работать с пустым пакетом параметров действий,

#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;
}

Демо

Как указывает HolyBlackCat, в c ++ 17 вы можете просто использовать выражение сгиба,

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

       (applyAction<as>(), ...);
}
0 голосов
/ 23 июня 2018

В C ++ 11, есть ли способ объявить переменную функцию, которая принимает пустой пакет параметров?

Да: есть и тривиально

template <Action...>
void applyActions()

Проблема в том, что в вашем случае сталкиваются с функцией, принимающей с одним или несколькими элементами

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

и когда вы звоните applyActions<as...>(); с непустым пакетом as..., оба шаблона совпадают.

Использование шаблонной функции с тем же именем, но с другим жанром аргумента (и значением по умолчанию)

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

это (ИМХО) чрезвычайно умный, дешевый и элегантный способ решения проблемы терминации.

...