关于 [conv.lval#2.2] 之后示例的问题

An issue about the example after [conv.lval#2.2]

例子是:

struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [&](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false);   // undefined behavior: access of x.n outside its lifetime
int n = g(true);    // OK, does not access y.n

相关规则是:

When an lvalue-to-rvalue conversion is applied to an expression E, and either

  1. E is not potentially evaluated, or
  2. the evaluation of E results in the evaluation of a member Ex of the set of potential results of E, and Ex names a variable x that is not odr-used by Ex([basic.def.odr])

the value contained in the referenced object is not accessed.

我对表达式 y.n 表示怀疑,它被标记为 n 的非 odr-used。

根据规则:

The set of potential results of an expression E is defined as follows:

  • If E is an id-expression ([expr.prim.id]), the set contains only E.
  • [...]
  • If E is a class member access expression ([expr.ref]) of the form E1 . template opt E2 naming a non-static data member, the set contains the potential results of E1.

根据项目符号 3,表达式 y.n 的潜在结果是 y 本身,而 n 确实是 y 的成员,这是潜在结果y.n 个。但是,我不同意 n 不是 odr-used.

根据这个规则:
basic.def.odr#4.2

A variable x whose name appears as a potentially-evaluated expression E is odr-used by E unless

  • x is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and E is an element of the set of potential results of an expression of non-volatile-qualified non-class type to which the lvalue-to-rvalue conversion ([conv.lval]) is applied.

左值到右值的转换应用于表达式y.n,其潜在结果仅包含对象表达式y 而不是 n。因此,根据 [basic.def.odr#4.2],名为 n 的变量被表达式 n ODR 使用。所以,g(true) 应该是未定义的行为。如何解释这个例子?是不是举错了?

您推理的问题是 [conv.lval]/3.2 没有要求 不使用 n。有问题的表达式是 E = (b ? y : x).n。潜在结果集为 {x, y}。当 b = true 时,E 的求值最终会导致 y 的求值。因此,我们可以设置E<sub>x</sub> = y,现在我们发现“对E的求值结果是对a的求值E 的潜在结果集的成员 E<sub>x</sub>”是正确的陈述。该子句现在只要求 E<sub>x</sub> = y 命名一个未在 E[=60= 中使用的变量]x</sub>。让我重复一遍,因为我认为这是你出错的地方:[conv.lval]/3.2 询问 E<sub>x</sub> odr-uses 本身(或者,实际上,它命名的变量)。我们正在寻找的是表达式 y 不 ODR 使用变量 y 的证明。成员访问 n 无关紧要。

好吧,我们继续看[basic.def.odr]/4

A variable x whose name appears as a potentially-evaluated expression E is odr-used by E unless

  • ...
  • x is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, and E is an element of the set of potential results of an expression of non-volatile-qualified non-class type to which the lvalue-to-rvalue conversion ([conv.lval]) is applied, or
  • ...

请注意,这里的 E 而不是 我们在 [const.lval]/3.2 中开始的 E = (b ? y : x).nE 是我们正在测试 y 的 odr-use 的表达式。我们将其命名为 E'。然后 E' = E<sub>x</sub> = y,因为我们再次检查表达式 y odr 是否使用变量y。条件的第一部分成立; y 是可用于常量表达式的非引用类型变量,它没有可变子对象。现在,E' = y 是原始 E 潜在结果集的一个元素(因为 E 是非易失限定的非 class 类型的表达式应用了左值到右值的转换)?是的,我们已经讨论过了,yE 的潜在结果之一。因此,E<sub>x</sub> 不使用 y。这就完成了 [conv.lval]/3.2 的前提条件:我们现在知道 (b ? y : x).n 在评估左值到右值转换时不会访问值 y.n。因此,没有UB。再次注意,n 基本上没有出现在我们的推理中。