关于 [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
- E is not potentially evaluated, or
- 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).n
。 E
是我们正在测试 y
的 odr-use 的表达式。我们将其命名为 E'
。然后 E' = E<sub>x</sub> = y
,因为我们再次检查表达式 y
odr 是否使用变量y
。条件的第一部分成立; y
是可用于常量表达式的非引用类型变量,它没有可变子对象。现在,E' = y
是原始 E
潜在结果集的一个元素(因为 E
是非易失限定的非 class 类型的表达式应用了左值到右值的转换)?是的,我们已经讨论过了,y
是 E
的潜在结果之一。因此,E<sub>x</sub>
不使用 y
。这就完成了 [conv.lval]/3.2
的前提条件:我们现在知道 (b ? y : x).n
在评估左值到右值转换时不会访问值 y.n
。因此,没有UB。再次注意,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: 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
- E is not potentially evaluated, or
- 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 expressionE
is odr-used byE
unless
- ...
x
is a variable of non-reference type that is usable in constant expressions and has no mutable subobjects, andE
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).n
。 E
是我们正在测试 y
的 odr-use 的表达式。我们将其命名为 E'
。然后 E' = E<sub>x</sub> = y
,因为我们再次检查表达式 y
odr 是否使用变量y
。条件的第一部分成立; y
是可用于常量表达式的非引用类型变量,它没有可变子对象。现在,E' = y
是原始 E
潜在结果集的一个元素(因为 E
是非易失限定的非 class 类型的表达式应用了左值到右值的转换)?是的,我们已经讨论过了,y
是 E
的潜在结果之一。因此,E<sub>x</sub>
不使用 y
。这就完成了 [conv.lval]/3.2
的前提条件:我们现在知道 (b ? y : x).n
在评估左值到右值转换时不会访问值 y.n
。因此,没有UB。再次注意,n
基本上没有出现在我们的推理中。