为模板重载函数模板 <typename...> class
Overloading a function template for a template <typename...> class
我不明白为什么这不能编译,你能给我一个简短的理由吗?
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
问题是 SignalArgs
没有声明函数模板的参数。它只是一个标识符,可以选择性地出现在 declarator 中,声明您的实际模板参数,即 Signal
。它与声明函数类型的声明符中的函数参数名称基本相同,例如:
void f(void(*fp)(int a, int b))
{}
这里,f
是一个带有参数 fp
的函数,它是一个指向带有两个 int
类型参数的函数的指针。标识符 a
和 b
是多余的,就像 SignalArgs
在您的原始示例中一样。它们可能会出现,但实际上并没有任何作用。
由于 SignalArgs
不是您的函数模板的模板参数,因此无法推导它(模板参数推导仅涉及推导函数模板参数的参数)。做你想做的事情的方法是引入一个单独的模板参数,它在你的函数参数类型中使用 signal
以这样一种方式可以推导出它:
template <template <typename...> class Signal, typename... SignalArgs, typename... Args>
void f(Signal<SignalArgs...>&& signal, Args&&... args)
{}
工作示例here
我不明白为什么这不能编译,你能给我一个简短的理由吗?
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
问题是 SignalArgs
没有声明函数模板的参数。它只是一个标识符,可以选择性地出现在 declarator 中,声明您的实际模板参数,即 Signal
。它与声明函数类型的声明符中的函数参数名称基本相同,例如:
void f(void(*fp)(int a, int b))
{}
这里,f
是一个带有参数 fp
的函数,它是一个指向带有两个 int
类型参数的函数的指针。标识符 a
和 b
是多余的,就像 SignalArgs
在您的原始示例中一样。它们可能会出现,但实际上并没有任何作用。
由于 SignalArgs
不是您的函数模板的模板参数,因此无法推导它(模板参数推导仅涉及推导函数模板参数的参数)。做你想做的事情的方法是引入一个单独的模板参数,它在你的函数参数类型中使用 signal
以这样一种方式可以推导出它:
template <template <typename...> class Signal, typename... SignalArgs, typename... Args>
void f(Signal<SignalArgs...>&& signal, Args&&... args)
{}
工作示例here