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

tem*_*boy 4 c++ language-lawyer lvalue-to-rvalue constexpr c++14

我很难理解这段代码(C++ 14草案标准[conv.lval]中的一个例子)是如何调用未定义的行为的g(false).为什么constexpr让程序有效?

另外,"不访问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
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 8

这是因为y.n没有使用odr,因此不需要访问y.nodr-use规则,3.2并说:

变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则生成不调用任何非平凡函数的常量表达式(5.19),并且如果x是一个对象,ex是表达式e的潜在结果集合的元素,其中 左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式

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

y
Run Code Online (Sandbox Code Playgroud)

ë将是(不同的表达E是用于覆盖在第3.2节中的第2段中定义):

(b ? y : x).n
Run Code Online (Sandbox Code Playgroud)

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

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

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

将左值到右值转换应用于表达式e和其中之一

并包括考试所属的以下子弹:

对e的评估结果是对e的潜在结果集合的成员ex的评估,并且ex为变量x命名,该变量x 不是由ex(3.2)使用的,

然后:

不访问引用对象中包含

由于缺陷报告1773,这适用于C++ 14草案标准.

  • 你确实从'g(true)`返回2但是程序不必访问名为`yn`的物理内存位置来获取该值. (3认同)