试图理解[basic.def.odr] / 2在C ++ 14(N4140) [英] Trying to understand [basic.def.odr]/2 in C++14 (N4140)

查看:110
本文介绍了试图理解[basic.def.odr] / 2在C ++ 14(N4140)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[basic.def.odr] / 2中的示例从以下句子开始:


在以下示例中,的
初始化器的潜在结果包含第一个S :: x子表达式,而不是
第二个S :: x子表达式。


从本段中的定义,我们如何推断n的初始化器包含第一个S :: x子表达式,而不是第二个S :: x子表达式?



编辑
请参阅上述示例的其余部分:

  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在这里是odr,所以
//需要一个定义


解决方案

我使用最近的基于N4296的github草案。实际的C ++ 14国际标准不包含这个例子,也不包括项目符号的编号。



我们分解初始化器中的表达式: b? (1,S :: x):f(S :: x)



表达式 :: x) int const 类型的左值。
表达式 f(S :: x)是后缀表达式,类型 int const



因此表达式 b? (1,S :: x):f(S :: x) int const 类型的左值。因此它满足[basic.def.odr] p2.5,并且潜在结果的集合是子表达式(1,S :: x) f(S :: x)



对于第一个子表达式(1,S :: x),我们通过p2.4去除括号。结果 1,S :: x 是逗号表达式。我们应用p2.6并且得到 S :: x 。现在,p2.1应用并告诉我们,这第一次出现是初始化器的一组潜在结果的一部分。



对于第二个子表达式 f(S :: x),只有p2.7适用。它的潜在结果集是空的,因此它不会对初始化器的一组潜在结果添加任何内容。






S :: x ,[basic.def.odr] p3


其名称显示为潜在计算表达式的变量 x
ex 除非将
转换为 x 生成常量表达式,所以 ex 不调用
任何非平凡函数,如果 x 是一个对象, ex 元素
表达式 e 的潜在结果集,其中
lvalue-to-rvalue转换应用于 e e 是一个
舍弃值表达式。


让我们把它分成以下几步:在表达式 ex x >构成odr使用,除非:


  1. ex


  2. ol>
  3. 将左值到右值转换应用到 x 会生成一个不调用任何非平凡函数的常量表达式

  4. ex 是潜在结果集中的一个元素 e 并且满足以下条件之一


    1. 左值到右值转换应用于 e

    2. e 是舍弃值表达式





请注意,是任何表达式 e [其中 e 满足某些要求]的潜在结果集合的元素,而不是所有表达式 e 它是的一部分。有关详情,请访问 std-



将步骤应用于第二次出现的`S :: x`



它是表达式 S :: x f(S :: x) b? (1,S :: x):f(S :: x)


  1. False (因为所有这些表达式都可能被评估),


  2. 必须满足以下所有条件: / b>


    1. True (因为将ltr转换应用于 S :: x 不会调用任何函数的常量表达式)

    2. 第二次出现 S :: x 是潜在结果集合中的一个元素 S :: x 本身。它不是 f(S :: x)的潜在结果的一部分。 以下任一项必须持有


      1. 为false (由于未应用左值到值的转换
      2. $ b>或false
        (因为 S :: x 不是废值表达式)





例外情况不适用,<$ c $



将步骤应用于第一次出现的`S :: x `



它是表达式的一部分 S :: x 1,S: :x (1,S :: x) (1,S :: x):f(S :: x)


  1. False (因为所有这些表达式都可能被评估),


  2. 必须满足以下所有条件: / b>


    1. True (因为将ltr转换应用于 S :: x 不调用任何函数的常量表达式)

    2. 第一次出现 S :: x 是它是初始化程序中的一部分的所有表达式的一组潜在结果的元素。 以下任一项必须持有


      1. true - 左值到右值转换肯定不适用于表达式 S :: x 1,S :: x (1,S: :x)。可以说,它应用于 b? (1,S :: x):f(S :: x)(见下文)

      2. 那些表达式是舍弃值表达式)




  3. ol>

    不清楚初始化是否应用了左值到右值的转换。可以认为必须读取lvalue-expression的值,以便从 int const 类型的表达式初始化 int code>。如果我们遵循这个假设,那么左值到右值的转换被应用到 b? (1,S :: x):f(S :: X)。第一次出现的 S :: x 是该表达式的潜在结果集合的一个元素(参见本答案的第一部分)。因此,上述的Bullet点3.0适用,并且 S :: x 不是在第一次出现时使用。



    您可以在Q& A中的初始化中找到大量关于左值到右值转换的信息初始化需要左值到右值转换?是 int x = x; UB?。这里的情况可能有点简单,因为rhs类型 int const 。这可能需要一个限定转换,它期望一个prvalue操作数(这可能暗中调用左值到右值的转换)。


    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)

    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) 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. Either ex is not potentially evaluated, or
    2. All of the following must be fulfilled:

      1. "applying the lvalue-to-rvalue conversion to x yields a constant expression that does not invoke any non-trivial functions" and
      2. "ex is an element of the set of potential results of an expression e" and either of the following holds:

        1. "either the lvalue-to-rvalue conversion is applied to e"
        2. "or e is a discarded-value expression"

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

    1. False (since all of these expressions are potentially evaluated), or
    2. All of the following must be fulfilled:

      1. True (since applying the l-t-r conversion to S::x yields a constant expression that does not invoke any functions) and
      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). Either of the following must hold:

        1. either false (since the lvalue-to-rvalue conversion is not applied when binding S::x to the function parameter of f)
        2. or false (since S::x is not a discarded-value expression)

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

    1. False (since all of these expressions are potentially evaluated), or
    2. All of the following must be fulfilled:

      1. True (since applying the l-t-r conversion to S::x yields a constant expression that does not invoke any functions) and
      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. Either of the following must hold:

        1. true - The lvalue-to-rvalue conversion is certainly not applied to the expressions S::x, 1, S::x, (1, S::x). It can be argued that it is applied to b ? (1, S::x) : f(S::x) (see below)
        2. or false (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). 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).

    这篇关于试图理解[basic.def.odr] / 2在C ++ 14(N4140)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆