【发布时间】:2019-01-09 23:25:48
【问题描述】:
举个例子:
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
}
错误如 cmets 中所述。
gcc 8.2.1 和 clang 7.0.1 被使用,并且不同意此示例中发生的情况。有人可以澄清一下吗?
否则,如果初始化列表有一个类型为 E 的元素,并且 T 不是引用类型或 它的引用类型与 E 引用相关,则对象或引用从该元素初始化(通过复制初始化复制列表初始化,或通过直接初始化直接列表初始化);如果需要缩小转换(见下文)将元素转换为 T,则程序格式错误。
否则,如果 T 是引用类型,则生成 T 引用的类型的纯右值。 纯右值通过复制列表初始化或直接列表初始化来初始化其结果对象,具体取决于关于初始化的那种,供参考。然后使用纯右值直接初始化引用。 [ 注意:与往常一样,如果引用类型是对非 const 类型的左值引用,则绑定将失败并且程序格式错误。 — 尾注 ]
给定类型“cv1 T1”和“cv2 T2”,如果 T1 与 T2 的类型相同,或者 T1 是 T2 的基类,则“cv1 T1”与“cv2 T2”引用相关强>。如果
“cv1 T1”与“cv2 T2”引用兼容 - T1 与 T2 相关,或
- T2 为“noexcept 函数”,T1 为“函数”,其他函数类型相同,
...and later on there's some (personally ambiguous) language on user-defined conversions:
例如:
如果引用是左值引用和初始化表达式
...
有一个类类型(即T2是一个类类型),其中T1与T2没有引用相关,可以转换为“cv3 T3”类型的左值,其中“cv1 T1”与“cv3 T3”引用兼容(通过枚举适用的转换函数([over.match.ref])并通过重载决议选择最佳转换函数来选择),
...
那么引用就绑定到...值转换的结果
...
否则,如果初始化表达式
...
具有类类型(即 T2 是类类型),其中 T1 与 T2 不引用相关,并且可以转换为“cv3 T3”类型的右值或函数左值,其中“cv1 T1”是引用兼容的使用“cv3 T3”
... 那么在第二种情况下转换的 ... 结果的值称为转换后的初始值设定项。如果转换后的初始化器是纯右值,则其类型 T4 调整为类型“cv1 T4”
...
否则:
- 如果 T1 或 T2 是类类型,并且 T1 与 T2 没有引用相关,用户定义的转换被认为是使用通过用户定义的转换复制初始化类型为“cv1 T1”的对象的规则 ... 调用转换函数的结果,如非引用复制初始化所述,然后用于直接初始化引用。 对于这种直接初始化,不考虑用户定义的转换。
...
否则,初始化表达式被隐式转换为“cv1 T1”类型的纯右值。应用临时实现转换并将引用绑定到结果。
这些规则非常微妙,我无法完全掌握每种情况。 对我来说,似乎应该生成一个纯右值(我同意 clang),但是引用初始化的语言以及与列表初始化的交互非常模糊。
【问题讨论】:
标签: c++ language-lawyer list-initialization