T*上的部分排序...和康斯特·

Partial ordering on T*... and const T&

本文关键字:排序 康斯特      更新时间:2023-10-16

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)

如果我们关注DR1395,我们会看到

如果A从函数参数包转换,而P不是参数包,则类型扣除失败。否则,使用使用使用结果类型P和A,然后按照17.9.2.5 [temp.deduct.type]中所述进行扣除。如果p是函数参数包,则将参数模板的每个剩余参数类型的类型A与函数参数pack的声明器ID的类型P进行比较。每个比较都将模板参数推论,以通过功能参数包扩展的模板参数包中的后续位置。类似地,如果A从函数参数包进行转换,则将其与参数模板的每个剩余参数类型进行比较。如果给定类型的扣除成功,则认为参数模板的类型被认为是至少与参数模板的类型一样专业。

[...]

如果在考虑上述函数模板F之后,函数模板F至少与函数模板g和vice-vice-a一样专业,并且如果g具有thailter param pack,则f f f function f具有相应的参数,以及如果f没有尾随的参数包,那么f比g。

更专业

根据我可以推断的内容,这意味着我们应该匹配从T*...扩展到const T&的每个单独类型,反之亦然。在这种情况下,T*const T&更专业(U*T成功,T*来自U失败)。

但是,编译器不同意。Clang认为这是模棱两可的,海湾合作委员会认为应该称呼第二个,这两种都与CPPReference不同。

正确的行为是什么?

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


const U&推导template <class ...T> int f(T*...);。这是失败的,无法从const U&推导T*-这是这里的包装并不重要的事实。因此,#2至少不如#1。


U*...推导template <class T> int f(const T&);,我们曾经具有"如果A是从函数参数pack转换的,而P不是参数包,则类型扣除失败。" - 这意味着我们甚至在尝试做其他任何事情之前就失败了。但是CWG 1395删除了该句子,所以我们继续前进,我们有新句子:

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

我们本身将U*与剩余的参数类型(即const T&)进行比较。这种推论成功了。因此,#1至少与#2一样专业。


结果,现在#1比#2更专业。您引用的关于落后参数包的报价不适用,因为我们没有每个功能模板至少与另一个功能一样专业的情况。另外,您引用的其他报价([temp.deduct.type]/10是关于推论功能类型,所以我认为它也不适用吗?尽管我也不确定该部分中的示例 - 或什么特定规则实际上是指。