提问人:JMC 提问时间:8/30/2023 最后编辑:Jan SchultkeJMC 更新时间:8/30/2023 访问量:86
当替换完整对象时,基类子对象的“透明替换”?
"Transparent replacement" of baseclass subobject when complete object is replaced?
问:
请考虑以下代码片段:
struct A { int n; };
struct B : A {};
B foo;
new (&foo) B { {42} }; // the new B transparently-replaces foo
int i = foo.n; // is this valid? Does this correctly refer to the new B's A.n ?
根据 [basic.life] p8,新的应该透明地取代 .但是,新的 -subobject 不应透明地替换,因为它是一个“可能重叠的子对象”,是一个基类子对象。B
foo
B
A
foo.A
但是,更换附件是否足够有效?B
我有两种可能的解释:
[...]原始对象的名称将自动引用新对象 [...]
因此,现在指的是新的.foo
B
[expr.ref] p6.2 对 -member 访问表达式有如下说明:.
如果是非静态数据成员 [...],则表达式 [] 指定第一个表达式指定的对象的相应成员子对象。
E2
E1.E2
因此应该参考新的 n。foo.n
foo
另一种解释是,它本身作为一个整体,被视为[basic.life]的措辞(见上文)中的“原始对象的名称”,因此它不是指新的,因为它本身是不可透明的可替换的,因为它的包含对象,即,是不可透明的。foo.n
int
int
A
如果有的话,这些解释中哪一种可能是正确的?
请记住,这是一个语言律师问题。问题不在于这是否实际有效,而在于标准的“法律条文”。
答:
第一种解释是正确的。在示例中:
B foo;
new (&foo) B { {42} };
B foo
可以透明地替换为在其存储中创建的类型的新对象,因为 [basic.life] p8 中的所有要求都已满足。
因此,对象的名称现在是指新对象,并且:B
foo
int i = foo.n; // this is now valid, and foo.n refers to the subobject in
// the new object also named foo
为什么第二种解释无效
foo.n
不能被认为是一个名字;它是组合多个名称的表达式。我不认为“名称”是由标准正式定义的,但这个词与标识符密切相关,如[lex.name]所示。它在 [dcl.pre] p4 中的使用方式表明,最多可以是 、 或 的名称。x
x::y
...x::y
无论名称是什么,(即 )都不是对象,而是非静态数据成员。你也可以写,使这一点更明显,并且是等价的。[expr.ref] p6.2 定义了对象表达式和非静态数据成员。n
A::n
foo.A::n
E1.E2
E1
E2
结论
透明替换是有效的。 不是透明的可替换的,但这个没关系,因为你把替换作为一个整体,然后抬头看看里面的替换。A::n
B
A::n
B
of 的子对象不必单独透明地替换即可实现。foo
评论