CWG 1815asked http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1815(有少量修改):
struct A {};
struct B { A&& a = A{}; };
B b1; // #1
B b2{A{}}; // #2
B b3{}; // #3
[...] #2
是聚合初始化,它绑定B::a
到初始化程序中的临时值b2
从而将其寿命延长到b2
. #3
是聚合初始化,但不清楚非静态数据成员初始化器中临时的生命周期是否为B::a
应该像这样延长寿命#2
或不,就像#1
.
根据 Issaquah (2014-02) 上有关该问题的注释,CWG 打算#3
表现得像#2
;也就是说,结构良好,并且执行临时对象的生命周期扩展b3.a
绑定。但在下一次 ISO 会议(拉珀斯维尔,2014 年 6 月)上,决议CWG 1696 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1696被通过,表面上解决了 CWG 1815,但adopting https://github.com/cplusplus/draft/commit/c93a904986ca0cdf9cd02bc5aafc0da258d6a47b语言似乎使#3不规范的 https://eel.is/c++draft/class.base.init#11:
11 - 从默认成员初始值设定项绑定到引用成员的临时表达式格式不正确。
然而,该子句下面的示例不考虑聚合初始化(如 CWG 1815 中所示),而仅考虑构造函数的初始化;具体来说,定义为 defaulted 的默认构造函数:
struct A {
A() = default; // OK
A(int v) : v(v) { } // OK
const int& v = 42; // OK
};
A a1; // error: ill-formed binding of temporary to reference
A a2(1); // OK, unfortunately
因此,虽然措辞看起来很清楚,但似乎也违背了委员会的意图,这可能是认为措辞有缺陷的理由。
从实施实践来看,我们可以see that https://godbolt.org/z/K9rGsP存在相当大的差异:
|
gcc |
clang |
MSVC |
ICC |
#1 |
❌ destroy |
✅ reject |
☠️ leak |
❌ destroy |
#2 |
✅ extend |
✅ extend |
✅ extend |
✅ extend |
#3 |
❌ extend |
❌ extend |
❌ extend |
❌ destroy |
(这里,“销毁”意味着临时对象在声明结束时被销毁,即不延长生命周期。✅ 表示符合,❌ 不符合,☠️ 明显的缺陷。)但是,除了 ICC 之外,编译器还同意延长生命周期在#3
,与目前的措辞相反。奇怪的是,尽管执行了生命周期延长,Clangwarns它无法这样做,表明开发人员认为在这种情况下标准需要延长生命周期:
警告:抱歉,不支持使用默认成员初始值设定项通过聚合初始化创建的临时对象的生命周期扩展;临时的生命周期将在完整表达式结束时结束 [-Wdangling]
Question
考虑到 CWG 所表达的意图以及实施差异,认为当前措辞有缺陷并依赖于 中发生的生命周期延长是否合理?#3
?委员会是否意识到这种差异,并且是否有可能在近期或中期得到解决(例如,作为 C++20 的 DR)?