【问题标题】:Partial ordering on T*... and const T&T*... 和 const T& 的部分排序
【发布时间】:2019-03-17 19:41:33
【问题描述】:

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 与函数形参包的 declarator-id 的类型 P 进行比较。每个比较推导出模板参数包中由函数参数包扩展的后续位置的模板参数。 类似地,如果 A 是从函数形参包转换而来的,则将其与形参模板的每个剩余形参类型进行比较。 如果给定类型的推导成功,则认为实参模板中的类型为至少与参数模板中的类型一样专业化。

[...]

如果在考虑以上之后,函数模板 F 至少与函数模板 G 一样特化,反之亦然,并且如果 G 有一个尾随参数包,而 F 没有对应的参数,并且如果F 没有尾随参数包,则 F 比 G 更特化。

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

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

正确的行为是什么?

【问题讨论】:

标签: c++ language-lawyer


【解决方案1】:

cppreference 对于此示例是正确的(这正是 CWG 问题以及 CWG 1825 中的示例)。让我们来看看这两种方式的扣除。


const U&amp; 推导出template &lt;class ...T&gt; int f(T*...);。这失败了,无法从const U&amp; 中推断出T* - 它是一个包的事实并不重要。所以 #2 至少不像 #1 那样专业。


U*... 推导出template &lt;class T&gt; int f(const T&amp;); 我们曾经有一个规则“如果A 是从函数参数包转换而来的,而P 不是参数包,则类型推导失败。” - 这意味着我们甚至在尝试做任何其他事情之前就失败了。但是 CWG 1395 删除了那句话,所以我们继续,我们有了新的句子:

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

我们将U* 本身与每个剩余的参数类型(即const T&amp;)进行比较。扣分成功。所以#1 至少和#2 一样专业。


因此,现在 #1 比 #2 更专业。您引用的关于尾随参数包作为后来的决胜局的引用不适用 - 因为我们没有每个函数模板至少与另一个函数模板一样专业的情况。还有你引用的另一句话([temp.deduct.type]/10 是关于推导函数类型,所以我认为它也不适用于这里?虽然我也不确定该部分中的示例 - 或者该特定规则的实际含义。

【讨论】:

  • 如果是这种情况,我如何才能使f(T, Ts...)f(Us...) 更专业?
  • 重读[temp.deduct.type]后,似乎确实与问题无关。它是关于如何从由它们组成的类型中推导出模板参数,例如void(int) 如何匹配到void(T)
  • @PasserBy 那...你知道吗,我不知道。
  • @T.C.不,我只是忘记了哪个是#1,哪个是#2:-D
  • T, Ts.../Us... 是分辨率的缺陷,早在 2017 年 1 月就已向核心反射器报告。
猜你喜欢
  • 2016-12-12
  • 1970-01-01
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多