【发布时间】:2019-04-20 20:10:49
【问题描述】:
考虑以下代码:
#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。
gcc 和 clang 似乎都可以使用双参数包本身,例如当第二个函数模板重载被移除时,两个编译器都会打印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 是错误的,并且该调用应被视为模棱两可,但我希望它验证这同样适用于此处。我也欢迎更详细的推理,因为函数模板部分排序规则对我来说似乎很不清楚。
【问题讨论】:
-
第一个 f 在我看来格式不正确。编译器如何确定性地推断出这两个包?
-
@RichardHodges -
{}和{int}(或任何其他作为函数参数传递的)。一包可以推断为空的......我想。 -
@RichardHodges 我添加了一些解释,为什么我认为双包本身已经不正确。
标签: c++ language-lawyer overload-resolution template-argument-deduction