什么是C ++ 14中使用的变量odr?

时间:2014-05-06 10:11:14

标签: c++ c++14 one-definition-rule

C ++ 14草案(N3936)在§3.2/ 3中声明:

  

变量x的名称显示为潜在评估的表达式ex,除非将lvalue-to-rvalue转换(4.1)应用于x,否则将生成一个不调用任何非平凡函数的常量表达式(5.19)并且,如果x是一个对象,则ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(4.1)应用于e,或者e是丢弃值表达式(子句) 5)。

这对我没有任何意义:如果表达式e丢弃值表达式取决于使用e的上下文。 表达式语句(第6.2节)中使用的每个表达式都是废弃值表达式。如果左值到右值转换应用于e,还取决于使用的上下文e

此外,表达式在另一个表达式的潜在结果集合中意味着什么。人们需要表达式相等的概念才能确定集合的成员资格。但是我们没有引用透明度,所以我看不出如何实现这一点。

为什么从C ++ 11改为C ++ 14?这怎么解释?就目前而言,它没有意义。

1 个答案:

答案 0 :(得分:26)

使用odr的目的

非正式地,变量的 odr-use 意味着以下内容:

  

如果程序中任何位置的任何表达式获取对象的地址或将引用直接绑定到对象,则必须定义此对象。

最新草案中的澄清

在最新版本的规范§3.2中已经澄清(见Draft C++14 on GitHub):

  

2表达式可能被评估,除非它是未评估的操作数(第5条)或其子表达式。表达式e的潜在结果集定义如下:

     
      
  • 如果e是id-expression(5.1.1),则该集仅包含e
  •   
  • 如果e是类成员访问表达式(5.2.5),则该集合包含对象表达式的潜在结果。
  •   
  • 如果e是指向成员的表达式(5.5),其第二个操作数是常量表达式,则该集合包含对象表达式的潜在结果。
  •   
  • 如果e具有表单(e1),则该集合包含e1的潜在结果。
  •   
  • 如果e是glvalue条件表达式(5.16),则该集合是第二个和第三个操作数的潜在结果集的并集。
  •   
  • 如果e是逗号表达式(5.18),则该集合包含右操作数的潜在结果。
  •   
  • 否则,该集合为空。
  •   
     

[注意:这个集合是一个(可能是空的)id表达式集合,每个表达式都是e或子表达式e

     

[示例:在以下示例中,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
     

-end example] -end note]

     

3变量x,其名称显示为可能评估的表达式ex,除非应用左值到右值,否则由ex 使用。转换(4.1)到x产生一个不调用任何非平凡函数的常量表达式(5.19),如果x是一个对象,ex是一组潜在结果的元素表达式e,其中左值到右值转换(4.1)应用于e,或e是丢弃值表达式(第5节)。

C ++ 11中的情况是什么?

C ++ 11中的

§3.2/ 2读取:

  

表达式可能会被评估,除非它是未评估的操作数(第5条)或其子表达式。名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(5.19)中的要求的对象,而左值到右值转换(4.1)是立即< / strong>已应用。

这些措辞的问题是DR 712。考虑这个例子:

struct S {
  static const int a = 1;
  static const int b = 2;
};
int f(bool x) {
  return x ? S::a : S::b;
}

由于S::aS::b是左值,因此条件表达式x ? S::a : S::b也是左值。这意味着左值到右值的转换不会立即应用于S::aS::b,而是应用于条件表达式的结果。这意味着通过C ++ 11的措辞,这些静态数据成员使用起来并且需要定义。但实际上只使用了这些值,因此不需要定义静态数据成员 - 声明就足够了。 C ++ 14草案的新措辞解决了这个问题。

新措辞是否解决了所有问题?

没有。在以下示例中,变量S::a仍然使用了odr:

struct S { static constexpr int a[2] = {0, 1}; };
void f() {
    auto x = S::a[0];
}

因此我提交了一个新的issue以将以下项目添加到§3.2/ 2:

  
      
  • 如果e是格式E1[E2]的glvalue下标表达式(5.2.1),则该集合包含E1的潜在结果。
  •