Mik*_*Lui 11 c++ language-lawyer list-initialization
鉴于这个例子:
int g_i = 10;
struct S {
operator int&(){ return g_i; }
};
int main() {
S s;
int& iref1 = s; // implicit conversion
int& iref2 = {s}; // clang++ error, g++ compiles fine:
// `s` is converted
// to a temporary int and binds with
// lvalue reference
int&& iref3 = {s}; // clang++ compiles, g++ error:
// cannot bind rvalue reference
// to lvalue
}
Run Code Online (Sandbox Code Playgroud)
错误如评论中所述.
使用gcc 8.2.1和clang 7.0.1,并且不同意本例中发生的情况.有人可以澄清一下吗?
否则,如果初始化程序列表具有 E类型的单个元素且T不是引用类型或其引用类型与E引用相关,则从该元素初始化对象或引用(通过复制初始化复制列表 - 初始化,或直接初始化直接列表初始化); 如果需要缩小转换(见下文)将元素转换为T,则程序格式不正确.
否则,如果T是引用类型,则生成由T引用的类型的prvalue.prvalue通过copy-list-initialization或direct-list-initialization初始化其结果对象,具体取决于引用的初始化类型.然后使用prvalue来直接初始化参考.[注意:像往常一样,如果引用类型是非const类型的左值引用,则绑定将失败并且程序格式错误. - 结束说明]
给定类型"cv1 T1"和"cv2 T2",如果T1与T2的类型相同,则"cv1 T1"与"cv2 T2"相关,或者T1是T2的基类."cv1 T1"与"cv2 T2"引用兼容,如果
- T1与T2相关,或者
- T2是"noexcept function"而T1是"function",其中函数类型相同,
...... 以及之后的用户定义转换有一些(个人模糊的)语言:
例如:
如果引用是左值引用并且初始化表达式
...
具有类类型(即,T2是类类型),其中T1不与T2引用相关,并且可以转换为类型为"cv3 T3"的左值",其中'CV1 T1’是参考兼容'CV3 T3’(这种转换被选择通过枚举适用转换函数([over.match.ref])和选择最佳的一个通过载分辨率),
...
然后引用绑定到转换的...值结果
...
否则,如果初始化表达式
...
具有类类型(即,T2是类类型),其中T1与T2不是引用相关的,并且可以转换为"cv3 T3"类型的右值或函数左值,其中"cv1 T1"与"cv3 T3"参考兼容
...然后在第二种情况下转换结果的值称为转换初始化器.如果转换的初始化程序是prvalue,则将其类型T4调整为键入"cv1 T4"
...
否则:
- 如果T1或T2是类类型且T1与T2无参考相关,则使用用户定义的转换使用"cv1 T1"类型的对象的复制初始化规则来考虑用户定义的转换. .如非参考拷贝初始化所述,调用转换函数的结果然后用于直接初始化引用.对于此直接初始化,不考虑用户定义的转换.
...
否则,初始化表达式被隐式转换为类型为"cv1 T1"的prvalue.应用临时实现转换,并将引用绑定到结果.
这些规则非常细微,我无法完全掌握每种情况.对我来说,似乎应该生成一个prvalue(我同意clang),但是参考初始化的语言和与列表初始化的交互非常模糊.
Bri*_*ian 10
让我们按照正确的顺序阅读标准,以便我们知道哪些部分适用于手头的情况.
[dcl.init]/17说:
初始化程序的语义如下...如果初始化程序是(非括号)braced-init-list或
=
braced-init-list,则对象或引用是列表初始化的(11.6.4)...
所以我们去[dcl.init.list](11.6.4).第3段说:
对象或类型引用的列表初始化
T
定义如下:( ...不适用的情况从此引用中删除...)否则,如果初始化列表具有单个元素类型E
且T
不是引用类型或其引用类型与引用相关E
...否则,如果T
是引用类型,T
则生成引用类型的prvalue .prvalue通过copy-list-initialization或direct-list-initialization初始化其结果对象,具体取决于引用的初始化类型.然后使用prvalue来直接初始化参考.[ 注意:像往常一样,如果引用类型是非const类型的左值引用,则绑定将失败并且程序格式错误.- 尾注 ]
根据[dcl.init.ref]/4:
给定类型的" CV1
T1
"和" CV2T2
"," CV1T1
"是参考相关于" CV2T2
"如果T1
是相同的类型T2
,或者T1
是一个基类的T2
.
因此,在您的代码中,引用的类型int
与初始化列表中的类型不是引用相关的,即S
.因此,通过[dcl.init.list]/3,int
生成一个类型的prvalue ,它采用该形式int{s}
.正如笔记所说,在这种情况下iref2
,程序是不正确的,因为它试图将非const左值引用绑定到prvalue.在这种情况下iref3
,程序应该编译,因为iref3
它被绑定到prvalue结果int{s}
.
归档时间: |
|
查看次数: |
197 次 |
最近记录: |