f1
和 f2
的演绎是否形成错误?
template<class... T, class U>
void f1(T..., U){}
template<class... T>
void f2(T..., int){}
int main()
{
f1(1);
f2(1);
return 0;
}
g接受两者,clang只接受 f2
,而msvc拒绝这两者 .
相关标准措辞:
当函数参数包出现在非推导的上下文([temp.deduct.type])中时,永远不会推导出该参数包的类型 .
非推导的上下文是:一个函数参数包,它不会出现在参数声明列表的末尾 .
所以似乎MSVC拒绝两者都是正确的?
这是否意味着即使您明确指定模板args,模板的任何实例化都将是格式错误的?
f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?
如果是这样的话,为什么要在第一时间允许这样的声明呢?
2 回答
这个特定问题DR1388有一个DR . 显然,GCC和CLANG似乎还没有实现它CLANG DR1388 .
否如果您明确指定模板参数,则不会发生扣减,因此上面显示的代码是合法的 .
我发现很难得到一个明确的答案 . 我可以说,
f1(1)
应该是 rejected 但f2(1)
应该是 accepted .那说:
clang -5.0接受两者
g -6接受两者
EDG 4.14拒绝两者
正如您所指出的,未在列表末尾出现的函数参数包是非推导的上下文([temp.deduct.type] p5):
和[temp.deduct.call] p1(通过CWG 1388修订)澄清了从不推断出这样的参数包 .
另外,[temp.arg.explicit] p3指定:
因此,考虑到
f2(1)
调用:包T是一个尾随模板参数包(虽然它不是一个尾随的函数参数包),因此它推断为空包并且该调用有效 .但是,对于
f1(1)
,包T也不是尾随模板参数包,因为它后跟U
,因此不会假定每个[temp.arg.explicit] p3为空包 . 因此,由于无法推断模板参数包T对f1(1)
的调用,它不应参与重载解析,并且调用应该失败 .请注意,在其他讨论中提出了几个类似的问题/示例,但它们都有微妙的不同:
f(0)
调用有效,因为有问题的包是一个尾随模板参数包,因此它属于我上面提到的情况 . 以下是CWG 1399的代码:int main(){
F(0); // 好
˚F<int>的(0,0,0); // 好
F(0,0,0); //错误
}
LLVM bug 21774讨论中的示例代码类似于CWG 1399示例,该包是一个尾随模板参数包 . 同样对于question .
CWG 2055,未解决,涉及类似的测试用例 . 无论什么时候解决,它的解决方案都可能会对这个问题中的例子的正确行为有所了解 . 以下是CWG 2055中提到的问题:
int main(){
˚F<>();
}