T * ...和const T&

时间:2019-03-17 19:41:34

标签: 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)

如果我们遵循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&更专业(来自T的{​​{1}}成功,来自U*的{​​{1}}失败)。

但是,编译器不同意。 Clang thinks it's ambiguousgcc thinks the second should be called,两者均与cppreference不同。

正确的行为是什么?

1 个答案:

答案 0 :(得分: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也是关于推导函数类型的,所以我认为它在这里也不适用吗?尽管我也不确定该部分中的示例-或该特定规则实际上意味着什么