考虑以下最小例子:
template<typename... A, typename R>
void f(A&&..., R(*)(A...)) {}
void g(int, char) {}
int main() {
f<int, char>(42, 'c', g);
}
参数包A
不是最后一个参数
无论如何,我认为R
可能是因为[temp.param]/11而从函数指针中推断出来的。
GCC(6.2)agrees with me就此而言,而clang(3.9)rejects the code并说它无法推断模板参数R
。
我的期望是错的,因此海湾合作委员会不应该接受它,或者是一个铿锵的问题?
答案 0 :(得分:1)
从上面提到的段落:
如果类模板,变量模板或别名模板的模板参数具有默认模板参数,则每个后续模板参数应具有提供的默认模板参数或者是模板参数包。如果主类模板,主变量模板或别名模板的模板参数是模板参数包,则它应该是最后一个模板参数。 函数模板的模板参数包不能跟随另一个模板参数,除非该模板参数可以从函数的参数类型列表([dcl.fct])中推导出来template或有一个默认参数([temp.deduct])。扣除指南模板([temp.deduct.guide])的模板参数没有默认参数可以从演绎指南模板的参数类型列表中进行推导。 [例如:
template<class T1 = int, class T2> class B; // error // U can be neither deduced from the parameter-type-list nor specified template<class... T, class... U> void f() { } // error template<class... T, class U> void g() { } // error
- 结束示例]
在这种情况下,template<typename... A, typename R>
无法从函数模板的参数类型列表中推断出来,因为:
void f(A&&..., R(*)(A...))
A&&...
贪婪,g
消耗A&&
而不是R(*)(A...)
说话迂腐,如temp.deduct.call-1:
对于发生在参数声明列表末尾的函数参数包,对每个剩余的调用参数执行推导,将函数参数包的declarator-id的类型P作为相应的函数模板参数类型。每个推导都推导出函数参数包扩展的模板参数包中后续位置的模板参数。 当函数参数包出现在非推导的上下文(
[temp.deduct.type]
)中时,永远不会推导出该参数包的类型。
如果P具有包含&lt; T&gt;的形式。或者&lt; i&gt;,然后将P的相应模板参数列表的每个参数Pi与A的相应模板参数列表的对应参数Ai进行比较。如果P的模板参数列表包含包扩展,则不是最后一个模板参数,整个模板参数列表是非推导的上下文。如果Pi是包扩展,则将Pi的模式与A的模板参数列表中的每个剩余参数进行比较。
并且无法在第三个示例中看到它。
拒绝它时,clang是对的。