c++ - 如何理解T&和T const&的偏序规则

标签 c++ language-lawyer template-argument-deduction function-templates partial-ordering

template <typename T>
void show(T&);       // #1
template <typename T>
void show(T const&); // #2

int main()
{
    int a = 0;
    show(a);        // #1 to be called
}

我对这些部分排序规则感到困惑。以下是一些引述:[temp.deduct.partial]/5

Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:

  • If P is a reference type, P is replaced by the type referred to.

  • If A is a reference type, A is replaced by the type referred to.

[temp.deduct.partial]/6

If both P and A were reference types (before being replaced with the type referred to above), determine which of the two types (if any) is more cv-qualified than the other; otherwise the types are considered to be equally cv-qualified for partial ordering purposes. The result of this determination will be used below.

[temp.deduct.partial]/7

Remove any top-level cv-qualifiers:

  • If P is a cv-qualified type, P is replaced by the cv-unqualified version of P.

  • If A is a cv-qualified type, A is replaced by the cv-unqualified version of A.

首先,void show(T&)void show(T const&) 都可以通过传递 int 左值来调用,所以我们需要使用偏序规则来决定哪个函数更匹配。然后,根据上面的引述,我们做一些改造。第 1 步:

T&       => T          #3
T const& => T const    #4

第 2 步:

T       => T    #5
T const => T    #6

#5 => #6#6 => #5,双向推演成功。 然后以下规则起作用:[temp.deduct.partial]/9

If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):

  • if the type from the argument template was an lvalue reference and the type from the parameter template was not, the parameter type is not considered to be at least as specialized as the argument type;

  • otherwise, if the type from the argument template is more cv-qualified than the type from the parameter template (as described above), the parameter type is not considered to be at least as specialized as the argument type.

所以#4#3更专业。对于给定值a,应该调用#2函数,但实际上调用了#1函数。为什么?难道是我的理解有问题?

最佳答案

在这种情况下,不使用“更专门”的规则,这是在排名隐式转换序列不能确定函数顺序的情况下的决胜局:[over.match.best]/1

Define ICSi(F) as follows:

[...]

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

  • (1.3) for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

  • [...]

  • (1.7) F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in [temp.func.order], or, if not that,

  • [...]

在这种情况下,仅对隐式转换序列进行排名就足以确定顺序,因此“或,如果不是”后面的所有内容都将被忽略。推导结果为 #1 的 (int&) 和 #2 的 (int const&),因此在这两种情况下,引用绑定(bind) (aint&aint const&) 会导致身份转换,无论 cv 限定如何:[over.ics.ref]/1

When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion ([over.best.ics]). [...]

但是,ICS1(#1) 是比 ICS1(#2) 更好的转换序列,因为 [over.ics.rank]/3 :

Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

  • [...]

  • (3.2) Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

    • [...]

    • (3.2.6) S1 and S2 are reference bindings ([dcl.init.ref]), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.

  • [...]

因此,ICS1(F1) 是比 ICS1(F2) 更好的转换序列,因此根据 [over.match.best]/(1.3) F1 优于 F2 (多于)。 [over.match.best]/(1.7)未使用规则。

<小时/>

“更专业”的规则用于相反的情况:

int const a = 0;
show(a);         // #2 should be called for a const lvalue

这次推导结果是int const&int const&,所以[over.match.best]/(1.7)正如您所观察到的,结果是 #2 是一个比 #1 更好的函数。

<小时/>

(强调我的,所有引用)

关于c++ - 如何理解T&和T const&的偏序规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59296834/

相关文章:

c++ - C++静态继承中的取消引用指针问题?

c++ - 如何在 Windows 7 上将 matlab 与 Qt 集成

c++ - 是否可以在 using 声明中引用用户定义的转换模板?

c++ - decltype 和隐藏外部名称的类成员名称之间的交互

c++ - 如何绕过 C++ 无法使用 lambda 匹配模板中的函数类型

c++ - 霍夫线变换 - 45 度角的伪影

c++ - Windows 下的确定性构建

c - 什么是 "namespace cleanliness",glibc 是如何实现的?

c++ - 在多参数情况下使用转换构造函数

c++ - 为什么模板参数推导会因重载函数而失败?