如果参数列表绑定到类,参数列表必须位于参数列表的末尾,如果参数列表是成员方法声明的一部分,则放宽约束。
换句话说,这个编译:
class C {
template<typename T, typename... Args, typename S>
void fn() { }
};
以下不是:
template<typename T, typename... Args, typename S>
class C { };
为什么第一种情况是正确的,第二种情况不是?
我的意思是,如果是合法的语法,那么两种情况都不应该是这样吗?
要清楚,真正的问题是我正在定义一个类似于以下类的类:
template<typename T, typename... Args, typename Allocator>
class C { };
将分配器类型作为最后一种类型将不胜感激,但我可以以某种方式解决它(无论如何,如果你有一个建议值得赞赏,也许你的优雅比我的优雅!!)。
那就是说,我收到了错误:
参数包'Args'必须位于模板参数列表的末尾
所以,我只是好奇地完全理解为什么它在某些情况下被接受,但它不在其他一些情况下。
Here是一个类似的问题,但它只是解释了如何解决问题,这对我来说非常清楚。
答案 0 :(得分:16)
它对函数模板有效,但只有当参数推导可以帮助编译器解析模板参数时,因为它代表你的函数模板示例实际上是无用的,因为
template<typename T, typename... Args, typename S> void fn() { }
int main() { fn<int, int, int>(); }
test.cpp: In function 'int main()':
test.cpp:2:32: error: no matching function for call to 'fn()'
int main() { fn<int, int, int>(); }
^
test.cpp:1:57: note: candidate: template<class T, class ... Args, class S> void fn()
template<typename T, typename... Args, typename S> void fn() { }
^
test.cpp:1:57: note: template argument deduction/substitution failed:
test.cpp:2:32: note: couldn't deduce template parameter 'S'
int main() { fn<int, int, int>(); }
编译器无法确定哪些模板参数属于参数包,哪些模板参数属于S
。事实上就像@ T.C.指出它实际上应该是语法错误,因为以这种方式定义的函数模板不能被实例化。
更有用的功能模板类似于
template<typename T, typename... Args, typename S> void fn(S s) { }
现在编译器能够明确地将函数参数s
与模板类型S
匹配,副作用是S
总是推导出 - 第一个之后的所有显式模板参数都属于Args
。
这些都不适用于(主要)类模板,参数未被推断且明确禁止:
来自草案n4567
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf
[temp.param] / 11
[...]如果是主类模板或别名的 template-parameter template是模板参数包,它应该是最后一个 模板参数。[...]
(如果推断出它们会在函数模板示例中模糊不清)。
答案 1 :(得分:11)
第一个是不对的。编译器只是错误并且无法诊断它。 [temp.param]/11:
不得遵循功能模板的模板参数包 通过另一个模板参数,除非该模板参数可以 从函数模板的 parameter-type-list 中推导出来或者有一个 默认参数(14.8.2)。
如果函数类型T(Args...)
对最终用户有意义,解决此问题的一种方法是使用部分特化:
template<class F, class Alloc> class C; //undefined
template<class T, class... Args, class Alloc>
class C<T(Args...), Alloc> {
// implementation
};
根据实际需求,类型擦除分配器也可能值得考虑。