简体   繁体   中英

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

The Example in [basic.def.odr]/2 starts with the following sentence:

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

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

Edit See below the remaining part of the Example referred 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

I'm using a recent github draft based on N4296. The actual C++14 International Standard does not contain this example, nor the numbering of bullet points. The specification relevant here is effectively the same.

We decompose 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 an lvalue of type int const . The expression f(S::x) is a postfix-expression, an lvalue of type int const .

Hence the expression b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) is an lvalue of type int const . It therefore fulfils [basic.def.odr]p2.5, and the set of potential results is the union of the sets of potential results of the sub-expressions (1, S::x) and f(S::x) .

For the first sub-expression (1, S::x) , we strip the parentheses via p2.4. The result 1, S::x is a comma expression. We apply p2.6 and get S::x . Now, p2.1 applies and tells us that this first occurrence is part of the set of potential results of the initializer.

For the second sub-expression f(S::x) , only p2.7 applies. Its set of potential results is empty, so it doesn't add anything to the set of potential results of the initializer.


As for the odr-use of S::x , [basic.def.odr]p3

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression 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 is applied to e , or e is a discarded-value expression.

Let's split this into steps: The occurrence of a variable x in an expression ex constitutes an odr-use unless:

  1. ex is not potentially evaluated, ex未被潜在评估,
    1. "applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions"
    2. " ex is an element of the set of potential results of an expression e " :
      1. " the lvalue-to-rvalue conversion is applied to e " 将左值到右值转换应用于e "
      2. " e is a discarded-value expression" e是弃值表达式"

Note that point 2 means "is an element of the set of potential results of ANY expression e [where e fulfils certain requirements]", rather than "all expressions e it is part of". Further discussion can be found on the std-discussion mailing list .

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

It is part of the expressions S::x , f(S::x) , b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) .

  1. (since all of these expressions are potentially evaluated), (因为所有这些表达式都可能被评估),
    1. (since applying the ltr conversion to S::x yields a constant expression that does not invoke any functions) (因为将 ltr 转换应用于S::x产生一个不调用任何函数的常量表达式)
    2. The only expression where the second occurrence of S::x is an element of the set of potential results is S::x itself. It is not part of the potential results of f(S::x) . :
      1. (since the lvalue-to-rvalue conversion is not applied when binding S::x to the function parameter of f ) (因为在将S::x绑定到f的函数参数时不应用左值到右值的转换)
      2. (since S::x is not a discarded-value expression) (因为S::x不是丢弃值表达式)

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

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

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

  1. (since all of these expressions are potentially evaluated), (因为所有这些表达式都可能被评估),
    1. (since applying the ltr conversion to S::x yields a constant expression that does not invoke any functions) (因为将 ltr 转换应用于S::x产生一个不调用任何函数的常量表达式)
    2. The first occurrence of S::x is an element of the set of potential results of all the expressions it is part of within the initializer. :
      1. - The lvalue-to-rvalue conversion is certainly not applied to the expressions S::x , 1, S::x , (1, S::x) . - 左值到右值的转换当然不适用于表达式S::x , 1, S::x , (1, S::x)It can be argued that it is applied to b ? (1, S::x) : f(S::x) b ? (1, S::x) : f(S::x) (see below)
      2. (none of those expressions are discarded-value expressions) (这些表达式都不是丢弃值表达式)

It is unclear whether or not initialization applies the lvalue-to-rvalue conversion. One can argue that the "value of the lvalue-expression" must be read in order to initialize the int from an expression of type int const . If we follow this assumption, then the lvalue-to-rvalue conversion is applied 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 set of potential results of that expression (see the first part of this answer). Hence, Bullet point 3.0 of the above applies, and S::x is not odr-used through the first occurrence.

You can find a lot of information on lvalue-to-rvalue conversion in initializations in the Q&A Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB? . The situation might be a bit easier here, since the rhs has type int const . This might require a qualification conversion, which expects a prvalue operand (this probably invokes the lvalue-to-rvalue conversion implicitly).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM