具有两个参数包的函数模板重载决策

use*_*163 9 c++ language-lawyer overload-resolution template-argument-deduction

请考虑以下代码:

#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);
}
Run Code Online (Sandbox Code Playgroud)

1在gcc 8.2上编译和打印,但由于调用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类模板推导失败,使用gcc 8.2,编译clang和msvc 另请参阅讨论:使用可变参数模板构造函数的演绎指南和可变参数类模板 - 不匹配的参数包长度

现在我也找到了问题的演绎指南和可变参数模板的答案,我假设gcc是错误的并且调用应该被认为是模棱两可的,但我想让它验证这适用于这里同样的方式.我也会更加详细地欢迎推理,因为功能模板偏序规则对我来说似乎很不清楚.

xsk*_*xzr 6

这里有两个问题.


首先,[temp.deduct.partial]/12(我也引用这个例子,因为它与你的相似)说:

在大多数情况下,如果并非所有模板参数都具有值,则推导失败,但是对于部分排序目的,模板参数可以保持不带值,前提是它不用于用于部分排序的类型.[注意:使用非推断上下文中使用的模板参数. - 尾注] [示例:

template <class T> T f(int);            // #1
template <class T, class U> T f(U);     // #2
void g() {
  f<int>(1);                            // calls #1
}
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

用于部分排序的类型T...根据[temp.deduct.partial]/3:

用于确定排序的类型取决于完成部分排序的上下文:

  • 在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型.

  • ...

因此,第一个未命名的模板参数包class...不会影响部分排序的结果.由于两个函数模板没有其他差异,因此两者都不比另一个更专业,从而导致模糊调用.

可能与GCC的49505错误有关.


其次,即使第二个功能模板不存在,呼叫仍然应该是格式错误的.根据[temp.arg.explicit]/3:

... 未以其他方式推导出的尾随模板参数包将被推导为空的模板参数序列......

只能将尾随模板参数包推导到空包,而第一个未命名的模板参数包class...不是尾随模板参数包.

GCC(bug 69623)和Clang(bug 26435)都存在此问题的错误.