T * ...和const T&的部分排序

Pas*_* By 15 c++ language-lawyer

cppreference要求以下内容

template <class ...T> int f(T*...);  // #1
template <class T>  int f(const T&); // #2
f((int*)0); // OK: selects #1
            // (was ambiguous before DR1395 because deduction failed in both directions)
Run Code Online (Sandbox Code Playgroud)

如果我们遵循DR1395,我们将看到

如果A是从函数参数包转换而P不是参数包,则类型推导失败。否则,使用 使用所得到的类型的P和A,扣然后作为在17.9.2.5 [temp.deduct.type]描述的方法进行。如果P是函数参数包,则将参数模板的每个其余参数类型的类型A与函数参数包的声明符ID的类型P进行比较。每次比较都会为模板参数包中由功能参数包扩展的后续位置推导模板参数。同样,如果A是从功能参数包转换而来的,则将其与参数模板的每个其余参数类型进行比较。 如果对给定类型成功推导,则认为参数模板中的类型至少与参数模板中的类型一样特殊。

[...]

在考虑上述因素后,如果功能模板F至少与功能模板G一样专门,反之亦然,并且G的尾随参数包中F没有对应的参数,并且F没尾随参数包,则F比G更专业。

根据我的推断,这意味着我们应该匹配从T*...const T&反之亦然的每个单独类型。在这种情况下,T*它比const T&TU*成功,T*U失败)更加专业。

但是,编译器不同意。Clang认为它是模棱两可的,gcc认为应该调用第二个,两者都与cppreference不同。

正确的行为是什么?

Bar*_*rry 8

对于该示例,cppreference是正确的(这恰恰是CWG问题以及CWG 1825中的示例)。让我们通过两种方式进行推论。


template <class ...T> int f(T*...);从推导const U&。此操作失败,不会是能够推断出T*const U&-事实上,这是一个包这里是无关紧要的。因此,#2至少不如#1专门。


推论template <class T> int f(const T&);U*...我们曾经有一个规则“如果A是从函数参数包转换而来的,P而不是参数包,则类型推导将失败。” -这意味着我们在尝试其他任何事情之前就失败了。但是CWG 1395删除了该句子,因此我们继续进行,然后有了新的句子:

同样,如果A是从功能参数包转换而来的,则将其与参数模板的每个其余参数类型进行比较。

我们将U*自身与其余每个参数类型进行比较const T&。推论成功了。因此,#1至少与#2一样专门。


结果,现在#1比#2更专业。您引用的有关后面的参数中断程序的参数包的引用不适用-因为我们不知道每个函数模板至少与另一个函数模板一样专门。您引用的另一个引号([temp.deduct.type] / 10也是关于推导函数类型的,所以我认为它在这里也不适用吗?尽管我也不确定该部分中的示例-或那是什么特定规则实际上意味着。

  • ``T,Ts ...`/`Us ...`问题是2017年1月向核心反射镜报告的分辨率缺陷。 (5认同)