The C++14 draft (N3936) states in §3.2/3:
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 (Clause 5).
This doesn't make any sense to me: If an expression e
is a discarded-value expression depends on the context, in which e
is used. Every expression used in an expression-statement (§6.2) is a discarded-value expression. If the lvalue-to-rvalue conversion is applied to e
also depends on the context e
is used in.
Moreover, what does it mean for an expression to be in the set of potential results of another expression. One needs a notion of equality of expressions to be able to determine membership of a set. But we don't have referential transparency, so I cannot see how this could be achieved.
Why was this changed from C++11 to C++14? And how should this be interpreted? As it stands, it doesn't make sense.
Informally, odr-use of a variable means the following:
If any expression anywhere in the program takes the address of or binds a reference directly to an object, this object must be defined.
In the latest version of the spec §3.2 has been clarified (see Draft C++14 on GitHub):
2 An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. The set of potential results of an expression
e
is defined as follows:
- If
e
is an id-expression (5.1.1), the set contains onlye
.- If
e
is a class member access expression (5.2.5), the set contains the potential results of the object expression.- If
e
is a pointer-to-member expression (5.5) whose second operand is a constant expression, the set contains the potential results of the object expression.- If
e
has the form (e1), the set contains the potential results of e1.- If
e
is a glvalue conditional expression (5.16), the set is the union of the sets of potential results of the second and third operands.- If
e
is a comma expression (5.18), the set contains the potential results of the right operand.- Otherwise, the set is empty.
[ Note: This set is a (possibly-empty) set of id-expressions, each of which is either
e
or a subexpression ofe
.[ Example: In the following example, the set of potential results of the initializer of
n
contains the firstS::x
subexpression, but not the secondS::x
subexpression.struct S { static const int x = 0; }; const int &f(const int &r); int n = b ? (1, S::x) // S::x is not odr-used here : f(S::x); // S::x is odr-used here, so // a definition is required
—end example ] —end note ]
3 A variable
x
whose name appears as a potentially-evaluated expressionex
is odr-used byex
unless applying the lvalue-to-rvalue conversion (4.1) tox
yields a constant expression (5.19) that does not invoke any nontrivial functions and, ifx
is an object,ex
is an element of the set of potential results of an expressione
, where either the lvalue-to-rvalue conversion (4.1) is applied toe
, ore
is a discarded-value expression (Clause 5).
§3.2/2 in C++11 reads:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.
The problem with these wordings was DR 712. Consider this example:
struct S {
static const int a = 1;
static const int b = 2;
};
int f(bool x) {
return x ? S::a : S::b;
}
Since S::a
and S::b
are lvalues the conditional expression x ? S::a : S::b
is also an lvalue. This means that the lvalue-to-rvalue conversion is not immediately applied to S::a
and S::b
, but to the result of the conditional expression. This means that by the wording of C++11, these static data members are odr-used and a definition is required. But actually only the values are used, hence it is not neccessary to define the static data members - a declaration would suffices. The new wording of draft C++14 solves this.
No. In the following example the variable S::a
is still odr-used:
struct S { static constexpr int a[2] = {0, 1}; };
void f() {
auto x = S::a[0];
}
Hence I submitted a new issue to add the following bullet to §3.2/2:
- if
e
is a glvalue subscripting expression (5.2.1) of the formE1[E2]
, the set contains the potential results ofE1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With