空包可变参数模板

时间:2018-06-23 09:59:59

标签: c++ c++11 templates variadic-templates template-meta-programming

假设我在编译时需要执行一些操作:

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 Example Here


为了实现扩展包终止,我必须声明虚拟函数:

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

这对我来说很“丑陋”,因为它可以调用通用类型。

在C ++ 11中,有没有办法声明一个接受空参数包的可变参数函数?

当然,它的声明不必使用所需的函数来引起歧义:

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

类似的东西:

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

Here这是一个不可编译的示例,因为通话不明确。但是它给出了我想要实现的目标。

2 个答案:

答案 0 :(得分:5)

以下一种结构化方式可以删除“丑陋”的默认值,它也删除了递归并可以与空的动作参数包一起使用

#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

正如HolyBlackCat指出的那样,在c ++ 17中,您可以只使用fold表达式,

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

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

答案 1 :(得分:1)

  

在C ++ 11中,是否有一种方法可以声明一个接受空参数包的可变参数函数?

是的:这很简单

template <Action...>
void applyActions()

问题是,在您的情况下,该函数与接受一个或多个元素的函数发生冲突

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

,当您使用非空的applyActions<as...>();包呼叫as...时,两个模板都匹配。

使用名称相同但类型不同的模板函数(以及默认值)

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

这(IMHO)是一种非常聪明,便宜且优雅的解决终端问题的方法。