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).