考虑以下代码:
#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()替换,那么两个编译器都无法编译,声称调用是不明确的。
如果将参数packs class... T替换为简单参数class T ( T...替换为T),则这两个编译器也都声称存在歧义。
在第一个例子中,哪一个编译器是标准的?我想这可以归结为函数模板的特定偏序规则,还是用这种方式使用双参数包已经不合适了?
编辑:
我的理解是,双包本身并不是格式错误的,因为在我的阅读中,temp.param 17.1/15似乎明确允许这样做,如果第二个包可以从函数参数中还原,这似乎是因为T...函数参数包的缘故。
还可以显式地指定第一个参数包的参数,但不是第二个参数包,因此并不总是这样(在模板参数推导之后)至少一个参数包是空的。我不知道这是否使程序的格式不正确,因为我不知道如何阅读例如temp.res 17.7/8.3在这种情况下。
gcc和clang对双参数包本身似乎都很好,例如,当第二个函数模板重载被删除时,两个编译器都打印1。但这可能是一个畸形的病例,不需要诊断。
此外,我假设使用类模板参数演绎,变量类模板可以定义一个可变构造函数模板,这将意味着一个类似于我的双参数包示例的构造函数候选,并且据我理解,相同的重载解析和模板参数演绎都发生在该上下文中。这个问题是由另一个有这样一个设置的问题引起的:变量类模板演绎失败与gcc 8.2,编译与clang和msvc (也请参阅有关该问题的讨论:带可变模板构造函数的演绎指南和可变类模板.不匹配的参数包长度 )
现在我也找到了演绎指南和可变模板问题的答案,我认为这意味着gcc是错的,这个呼吁应该被认为是模棱两可的,但我想让它验证一下,这同样适用于这里。我也欢迎更详细的推理,因为函数模板偏序规则在我看来非常不清楚。
发布于 2018-11-18 16:28:52
这里有两个问题。
首先,[temp.deduct.partial]/12 (我也引用了这个例子,因为它与您的相似)说:
在大多数情况下,如果不是所有模板参数都有值,扣减就会失败,但出于偏序的目的,模板参数可能仍然没有值,只要它不用于用于偏序的类型中。 注:非推导上下文中使用的模板参数被认为是使用的.- end注意事项
用于偏序的类型是T... (根据[temp.deduct.partial]/3 )
用于确定排序的类型取决于执行偏序的上下文:
因此,第一个未命名的模板参数pack class...不影响偏序的结果。由于这两个函数模板没有其他不同之处,所以两者都不是比另一个更专门化,从而导致了一个模糊的调用。
本可能与GCC的bug 49505有关。
第二,即使第二个函数模板不存在,调用仍然应该是不正确的。根据[temp.arg.explicit]/3的说法:
..。未导出的尾随模板参数包将被推导为模板参数的空序列.
只能将尾随模板参数包推断为空包,而第一个未命名的模板参数包class...不是尾随模板参数包。
https://stackoverflow.com/questions/53358165
复制相似问题