为模板<typename ...>类

时间:2019-12-09 12:44:49

标签: c++ templates overloading c++17 variadic-templates

我不明白为什么它不能编译,您能给我一个简单的理由吗?

template <typename... Args>
class Signal{};

template <template <typename... SignalArgs> class Signal, typename... Args>
void f(Signal<SignalArgs...>&& signal, Args&&... args)
{}

gcc提供的错误是:

error: 'SignalArgs' was not declared in this scope; did you mean 'Signal'?
   11 | void f(Signal<SignalArgs...>&& signal, Args&&... args)
      |               ^~~~~~~~~~
      |               Signal
<source>:11:25: error: expected parameter pack before '...'
   11 | void f(Signal<SignalArgs...>&& signal, Args&&... args)
      |                         ^~~
<source>:11:28: error: template argument 1 is invalid
   11 | void f(Signal<SignalArgs...>&& signal, Args&&... args)
      |       

更重要的是,编写这种重载的正确方法是什么?请注意,我需要两个f的变体-一个在讨论中,另一个是template <typename F> void f(F&&);我绝对不希望任何Signal的实例,包括Signal<>,进入通用过载。

在Godbolt上在线尝试:https://godbolt.org/z/Xawz6G

1 个答案:

答案 0 :(得分:2)

问题是SignalArgs没有声明函数模板的参数。它只是一个标识符,可以有选择地出现在declarator中,该标识符声明您的实际模板参数,即Signal。基本上与声明函数类型的声明器中函数参数的名称相同:

void f(void(*fp)(int a, int b))
{}

在这里,f是一个带有参数fp的函数,该参数是一个指向带有两个int类型的参数的函数的指针。标识符ab是冗余的,与原始示例中的SignalArgs相同。它们可能会出现,但实际上并没有任何作用。

由于SignalArgs不是函数模板的模板参数,因此无法推论(模板参数推论仅涉及推导函数模板参数的论点本身)。执行所需操作的方法是引入一个单独的模板参数,该模板参数以可以推论的方式在函数参数signal的类型中使用:

template <template <typename...> class Signal, typename... SignalArgs, typename... Args>
void f(Signal<SignalArgs...>&& signal, Args&&... args)
{}

工作示例here