Trying to understand [basic.def.odr] / 2 in C ++ 14 (N4140)

The example in [basic.def.odr] / 2 begins with the following sentence:

In the following example, the set of potential results Initializer n contains the first subexpression S :: x, but not the second subexpression S :: x.

From the definitions in this section, how can we conclude that the initializer n contains the first subexpression S :: x, but not the second subexpression S :: x?

Edit See below for the remainder of the example above:

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 
+2
source share
1 answer

I am using a recent github project based on N4296. The actual international standard C ++ 14 does not contain this example, as well as the numbering of marker points. The relevant specification is virtually the same here.

Expand the expression in the initializer: b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x)

The expression (1, S::x) is a value l of type int const . The expression f(S::x) is a postfix expression, lvalue of type int const .

Therefore, the expression b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) is a value l of type int const . Therefore, it executes [basic.def.odr] p2.5, and the set of potential results is a union of the sets of potential results of the subexpressions (1, S::x) and f(S::x) .

For the first subexpression (1, S::x) we divide the parentheses by p2.4. Result 1, S::x is a comma expression. We apply p2.6 and get S::x . Now p2.1 is applied and tells us that this first occurrence is part of the many potential initializer results.

For the second subexpression f(S::x) , only p2.7 is applied. Its set of potential results is empty, so it does not add anything to the set of potential initializer results.


Regarding the odr use of S::x , [basic.def.odr] p3

The variable x whose name is displayed as a potentially evaluated expression ex is odr-used by ex , if the lvalue-to-rvalue to x transformation is not applied, it gives a constant expression that does not call any nontrivial functions and, if x is an object, ex is an element of a set of potential the results of an expression e , where either the lvalue-to-rvalue conversion is applied to e , or e is the dropped value.

Let me break this down into steps: the appearance of the variable x in the ex expression is odr-use, if only:

  • Either ex not evaluated potentially, or
  • All of the following should be done:
    • ", applying the conversion of lvalue-to-rval to x , produces a constant expression that does not call any non-trivial functions" and
    • " ex is an element of the set of potential results of expression e " and one of the following conditions is true :
      • " either the lvalue-to-rale conversion applies to e "
      • " or e is an expression with a discarded value"

Note that point 2 means that "is an element of the set of potential results for ANY expressions e [where e fulfills certain requirements]" and not "all expressions e are part". Further discussion can be found in the std discussion of the newsletter .

Applying steps to the second occurrence of `S :: x`

Is this part of the expressions S::x , f(S::x) , b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) .

  • False (since all of these expressions are potentially evaluated), or
  • All of the following should be done:
    • True (since applying the ltr to S::x conversion gives a constant expression that does not call the any function) and
    • The only expression in which the second occurrence of S::x is an element of the set of potential results is S::x . It is not part of the potential results of f(S::x) . Any of the following values ​​must contain :
      • or false (since the lvalue-to-rale conversion is not applied when binding S::x to the functional parameter f )
      • or false (since S::x not an expression of the discarded value)

The exception does not apply, S::x is odr-used through its second occurrence.

Applying steps to the first occurrence of `S :: x`

Is this part of the expressions S::x , 1, S::x , (1, S::x) , b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) .

  • False (since all of these expressions are potentially evaluated), or
  • All of the following should be done:
    • True (since applying the ltr to S::x conversion gives a constant expression that does not call the any function) and
    • The first occurrence of S::x is an element of the set of potential results of all expressions that it is part of inside the initializer. Any of the following values ​​must contain :
      • true - the lvalue-to-rvalue transformation, of course, does not apply to the expressions S::x , 1, S::x , (1, S::x) . It can be argued that it applies to b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) (see below).
      • or false (none of these expressions is an expression of discarded values)

It is unclear whether lvalue-to-rvalue conversion initialization is applied. It can be argued that the "value of lvalue-expression" must be read to initialize int from an expression of type int const . If you follow this assumption, then the lvalue-rvalue transform applies to b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) . The first occurrence of S::x is an element of the many potential results of this expression (see the first part of this answer). Therefore, Bullet 3.0 above applies, and S::x not used as the first element in the first occurrence.

You can find a lot of information about lvalue-to-rvalue conversion when initializing in Q & A Does initialization include lvalue-to-rvalue conversion? This is int x = x; UB? . The situation here may be a little easier, since rhs is of type int const . This may require a qualification transformation that awaits the prvalue operand (this probably causes an implicit lvalue-rvalue transformation).

+10
source

All Articles