【发布时间】:2021-09-26 08:39:21
【问题描述】:
我想创建两个具有相互成员引用的对象。稍后它可以扩展到例如N 个引用对象的闭环,其中 N 在编译时是已知的。
最初的尝试是使用最简单的结构 A 缺少任何构造函数,这使它成为一个聚合(v 模拟一些有效负载):
struct A {
const A & a;
int v = 0;
};
struct B {
A a1, a2;
};
consteval bool f()
{
B z{ z.a2, z.a1 };
return &z.a1 == &z.a2.a;
}
static_assert( f() );
很遗憾,由于错误,编译器不接受它:
accessing uninitialized member 'B::a2'
这实际上很奇怪,因为没有进行真正的读取访问,只记住了它的地址。演示:https://gcc.godbolt.org/z/cGzYx1Pea
在A添加构造函数后问题解决,不再聚合:
struct A {
constexpr A(const A & a_) : a(a_) {}
constexpr A(const A & a_, int v_) : a(a_), v(v_) {}
const A & a;
int v = 0;
};
现在所有编译器都接受程序,演示:https://gcc.godbolt.org/z/bs17xfxEs
令人惊讶的是,看似等效的程序修改使其有效。在这种情况下,标准中是否真的有一些措辞阻止使用聚合?究竟是什么让第二个版本安全并被接受?
【问题讨论】:
-
const A &a是一个问题,因为该字段必须初始化(它是 const),并且默认 ctor 无法为其提供任何好的值,因此被删除。
标签: c++ language-lawyer c++20