c++ - 试图了解C++ 14(N4140)中的[basic.def.odr]/2

标签 c++ language-lawyer c++14

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

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.



根据本段中的定义,我们如何推断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 is odr-used here, so
                     // a definition is required

最佳答案

我正在使用基于N4296的最新github草案。实际的C++ 14国际标准不包含此示例,也不包含项目符号的编号。这里相关的规范实际上是相同的。

我们在初始值设定项中分解表达式:b ? (1, S::x) : f(S::x)
表达式(1, S::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的odr-use,[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.



让我们将其分为几个步骤:表达式x中出现的ex变量构成了odr-use,除非:

  • 可能无法评估ex

  • 必须满足以下所有条件:

  • “将左值到右值转换应用于x会产生一个不调用任何非平凡函数的常数表达式”和
  • ex是表达式e的潜在结果集的元素,并且以下任意一项成立:

  • “将左值到右值转换应用于e
  • “或e是一个废弃值表达式”



  • 请注意,第2点表示“是ANYt表达式e [其中e满足某些要求的情况]的潜在结果集中的元素”,而不是“它是其中的所有表达式e的一部分”。可以在std-discussion mailing list上找到更多讨论。

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

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

  • 为假(因为所有这些表达式都可能被求值)或

  • 必须满足以下所有条件:

  • True(因为将tl转换为S::x会产生不调用任何函数的常量表达式)和
  • 第二次出现S::x是潜在结果集的元素的唯一表达式是S::x本身。它不是f(S::x)的潜在结果的一部分。以下任一条件必须成立:

  • 为false(因为将S::x绑定(bind)到f的功能参数时未应用左值到右值转换)
  • 或false(因为S::x不是舍弃值表达式)



  • 该异常不适用,S::x通过其第二次出现而被使用。

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

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

  • 为假(因为所有这些表达式都可能被求值)或

  • 必须满足以下所有条件:

  • True(因为将tl-r转换应用于S::x会产生一个不调用任何函数的常量表达式)和
  • S::x的首次出现是初始化程序中所有表达式的潜在结果集中的一个元素。以下任一条件必须成立:

  • true-左值到右值的转换当然不会应用于表达式S::x1, S::x(1, S::x)。可以说它被应用于b ? (1, S::x) : f(S::x)(见下文)
  • 或false(这些表达式都不是舍弃值表达式)



  • 初始化是否应用左值到右值转换尚不清楚。可以说,必须读取“左值表达式的值”,以便根据int类型的表达式来初始化int const。如果遵循此假设,则将左值到右值转换应用于b ? (1, S::x) : f(S::X)S::x的首次出现是该表达式的潜在结果集中的一个元素(请参阅此答案的第一部分)。因此,上面的项目符号点3.0适用,并且在第一次出现时不使用S::x

    您可以在Q&A Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB?的初始化中找到很多有关左值到右值转换的信息。这里的情况可能会容易一些,因为rhs的类型为int const。这可能需要限定转换,该转换需要一个prvalue操作数(这可能隐式调用从左值到右值的转换)。

    关于c++ - 试图了解C++ 14(N4140)中的[basic.def.odr]/2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29997142/

    相关文章:

    c++ - 如何使用 OpenCV 在 C++ 中将 vector vector 的结构复制到另一个 vector

    functional-programming - 什么是 "strongly moded"编程语言?

    c - 指向 char 的指针,不同的术语

    c++ - (C++14) lambda 数组 : error: 'name' declared as array of 'auto'

    c++ - 模板重载解决奇数 VS2013

    c++ - 如何在 std::vector 中查找模式

    c++ - Qt 阻塞调用以显示对话框?

    c++ -- 如何实现一个支持插件的框架

    c++ - 将十进制数转换为有理数时的精度问题

    c++ - 将单个对象视为具有一个元素的数组,采用尾数指针