3
#include <iostream>
struct Data{};
struct Test{
    Test() = default;
    Test(Data){}
};
int main(){
  Data d;
  Test const& rf = d;
}

考虑上面的代码,标准说:

否则:

  • 5.2.2.1 如果T1 或 T2 是类类型并且 T1 与 T2 没有引用相关,则用户定义的转换被认为是使用通过用户定义的转换来复制初始化类型为“cv1 T1”的对象的规则([ dcl.init]、[over.match.copy]、[over.match.conv]);如果相应的非参考复制初始化格式错误,则程序格式错误。调用转换函数的结果,如针对非引用复制初始化所描述的,然后用于直接初始化引用。对于这种直接初始化,不考虑用户定义的转换。
  • 5.2.2.2 否则,初始化表达式被隐式转换为“cv1 T1”类型的纯右值。应用临时实现转换并将引用绑定到结果。

那么,上述案例服从哪个项目符号?初始化表达式Test通过转换构造函数Test::Test(Data)而不是conversion function. 但是请注意 中强调的部分5.2.2.1,它表示调用转换函数的结果然后用于直接初始化引用。在我的示例中,被调用的函数是转换构造函数,因此,结果是转换构造函数的结果。

问题一:

哪个项目符号涵盖了我的示例?5.2.2.1还是5.2.2.2


5.2.1.2 有一个类类型(即T2是一个类类型),其中T1与T2没有引用相关,可以转换为“cv3 T3”类型的右值或函数左值,其中“cv1 T1”是与“cv3 T3”参考兼容(参见[over.match.ref]),

考虑一下子弹5.2.1.2,它已经涵盖了类型T2是类类型的情况,并且可以转换为cv3 T3through conversion function

问题 2:

那么,5.2.2.1coversT2是类类型是不是多余,可以通过转换成destination类型呢conversion function,这样的case已经覆盖了5.2.1.2

4

1 回答 1

2

第一期

[dcl.init.ref]/5.2.2.1 适用于此。它是涵盖用户定义转换的段落。可接受的转换机制之一是 16.3.1.4 [over.match.copy],它可以在T1. 使用此构造函数转换值,并将生成的临时值绑定到引用。

[dcl.init.ref]/5.2.2.2 适用于包括用户定义转换的隐式转换的情况,例如加宽数值转换。

第 2 期

来自 [dcl.init.ref]:

(5.2.1) 如果初始化表达式

...

(5.2.1.2) 有一个类类型(即T2是一个类类型),其中T1与 没有引用相关T2,可以转换为“<em>cv3 T3”类型的右值或函数左值,其中“<em> cv1 T1”与“<em>cv3 ”引用兼容T3(见 16.3.1.6),

跳到 16.3.1.6 [over.match.ref],这里有很多散文,但这是唯一相关的部分:

(1) ... 假设“对cv1 T的引用”是被初始化的引用的类型,“<em>cv S”是初始化表达式的类型,具有S类类型,候选函数选择如下:

(1.1)S考虑其转换函数及其基类。...

本节的其余部分详细说明了哪些转换函数S可以使用,但这对于示例代码中的情况并不重要。[over.match.ref] 只考虑用于初始化引用的值类型上的转换运算符,这里不是这种情况——Data没有隐式转换运算符。本节未提及转换T.

因此 [over.match.ref] 和扩展 [dcl.init.ref]/5.2.1.2 不适用于这种情况。

于 2020-08-18T03:55:34.873 回答