考虑以下代码:
#include<iostream>
template<class..., class... T>
int f(T...) { return 1; }
template<class... T>
int f(T...) { return 2; }
int main()
{
std::cout << f(1);
}
在gcc 8.2上编译并打印出1,但因调用f(1)而在clang 7上无法编译,因为其模棱两可。如果将调用替换为f(),则两个编译器都无法编译,声称调用不明确。如果将参数包class...T替换为简单参数class T(和T…替换为T),则两个编译器也会声称存在歧义。在第一个示例中,哪个编译器符合标准?我想这取决于函数模板的具体部分排序规则,或者是否已经以这种方式使用双参数包是非法的?我的理解是,双重包本身并不是非法的,因为在我的阅读中,如果第二个包可以从函数参数推导出来,[temp.param] 17.1/15似乎明确允许这样做,由于T…函数参数包的情况似乎是如此。还可以明确指定第一个参数包的参数,尽管不能指定第二个参数包,因此在模板参数推导后至少有一个参数包为空的情况并不总是成立。我不确定这是否使程序非法,因为我不知道如何在这种情况下阅读例如[temp.res] 17.7/8.3。两个编译器似乎都对双重参数包本身没有问题,例如当删除第二个函数模板重载时,两个编译器都打印1。但这可能是一种不需要诊断的非法情况。此外,我认为,通过类模板参数推导,可变类模板可以定义具有可变模板构造函数的构造函数候选项,该构造函数候选项类似于我的双参数包示例,并且就我所知,在该上下文中进行相同的重载分辨率和模板参数推导。这个问题是由另一个具有这样设置的问题引起的:Variadic class template deduction fails with gcc 8.2, compiles with clang and msvc 对于该讨论,请参见: Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths。现在我也找到了Deduction guide and variadic templates的答案,我认为这意味着gcc是错误的,应该认为调用是模棱两可的,但我想要验证它是否适用于这里以同样的方式。我也希望更详细地解释一下推理,因为函数模板部分排序规则对我来说似乎非常不清楚。
{}
和{int}
(或者其他作为函数参数传递的内容)。一个空包可以被推断出来...我想。 - StoryTeller - Unslander Monica