首页 > 解决方案 > 为模板重载函数模板班级

问题描述

我不明白为什么这不能编译,你能给我一个简短的理由吗?

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

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

解决方案


问题是SignalArgs没有声明函数模板的参数。它只是一个标识符,可以选择出现在声明实际模板参数的声明器中,即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)
{}

这里的工作示例


推荐阅读