4
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

在完成偏序之前,对用于偏序的类型执行某些转换:

  • 如果P是引用类型,P则替换为引用的类型。

  • 如果A是引用类型,A则替换为引用的类型。

[temp.deduct.partial]/6

如果PA都是引用类型(在被上面提到的类型替换之前),确定这两种类型中的哪一种(如果有的话)比另一种更具 cv 限定性;否则,这些类型被认为是同等 cv 限定的,用于部分排序目的。下面将使用该确定的结果。

[temp.deduct.partial]/7

删除任何顶级 cv 限定符:

  • 如果P是 cv 限定类型,P则替换为 的 cv 不限定版本P

  • 如果A是 cv 限定类型,A则替换为 的 cv 不限定版本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

如果对于给定类型,推导在两个方向上都成功(即,在上述转换之后类型相同)并且两者P都是 A引用类型(在被上述类型替换之前):

  • 如果参数模板中的类型是左值引用,而参数模板中的类型不是,则参数类型不被认为至少与参数类型一样特化;

  • 否则,如果参数模板中的类型比参数模板中的类型更具 cv 限定性(如上所述),则参数类型不被认为至少与参数类型一样特化。

那么#4更专业呢#3。对于给定的 value a#2应该调用#1function,但实际上调用的是 function。为什么?我的理解有问题吗?

4

1 回答 1

5

在这种情况下,不使用“更专业”的规则,这是一个决胜局,以防对隐式转换序列进行排序并不能确定函数的顺序:[over.match.best]/1

定义 ICS i (F) 如下:

[...]

鉴于这些定义,如果对于所有参数i,ICS i (F1) 不是比 ICS i (F2) 更差的转换序列,则可行函数 F1 被定义为比另一个可行函数 F2 更好的函数 ,然后

  • ( 1.3 ) 对于某些参数j,ICS j (F1) 是比 ICS j (F2) 更好的转换序列,或者,如果不是这样,

  • [...]

  • ( 1.7 ) F1 和 F2 是函数模板特化,根据 [temp.func.order] 中描述的偏序规则,F1 的函数模板比​​ F2 的模板更特化,或者,如果不是,

  • [...]

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

当引用类型的参数直接绑定到参数表达式时,隐式转换序列是恒等转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生的-到基础转换([over.best.ics])。[...]

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

除非以下规则之一适用,否则两个相同形式的隐式转换序列是无法区分的转换序列:

  • [...]

  • ( 3.2 ) 标准转换序列 S1 是比标准转换序列 S2 更好的转换序列 if

    • [...]

    • ( 3.2.6 ) S1 和 S2 是引用绑定 ([dcl.init.ref]),并且引用所引用的类型是相同的类型,除了顶级 cv 限定符和引用初始化的类型by S2 的引用比由 S1 初始化的引用所引用的类型更具有 cv 限定

  • [...]

因此,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 更好的函数。


(强调我的,所有报价)

于 2019-12-12T10:09:28.917 回答