理解左值到右值转换的例子

Understanding the example on lvalue-to-rvalue conversion

我很难理解此代码(来自 C++14 草案标准 [conv.lval] 的示例)如何为 [=11 调用未定义的行为=].为什么 constexpr 使程序有效?

另外,"does not access y.n"是什么意思?在对 g() 的两次调用中,我们都返回了 n 数据成员,那么为什么最后一行说它不访问它?

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 due to access of x.n outside its
                  // lifetime
int n = g(true);  // OK, does not access y.n

这是因为 y.n 未使用 odr,因此不需要访问 y.n 3.2 中涵盖了 odr-use 的规则并说:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression

请注意,Ben Voigt 发表了一些有用的评论,稍微澄清了这一点。所以这里的工作假设是 x 将是:

y

e 将是(定义 e 的不同表达式包含在第 3.2 节的第 2 段中):

(b ? y : x).n

y 产生常量表达式,左值到右值的转换应用于表达式 e.

因为 f 产生一个 lambda,它通过引用捕获 f 的局部变量 x 一旦调用 f 就不再有效,因为 xf里面的一个自动变量。由于 y 是一个 常量表达式 它的行为就好像 y.n 没有被访问,因此我们没有相同的生命周期问题。

您的示例包含在 N3939 部分 4.1 [conv.lval] 并且在该示例之前它说:

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

并包含考试所属的以下要点:

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 (3.2),

然后:

the value contained in the referenced object is not accessed

由于 defect report 1773,这已应用于 C++14 标准草案。