静态constexpr使用或不使用?

时间:2014-10-04 18:58:28

标签: c++ c++11 constexpr one-definition-rule

为什么以下内容适用于gcc但不适用于clang,( see it live ):

constexpr int giveMeValue() { return 42; }

struct TryMe {
  static constexpr int arr[1] = {
      giveMeValue()
  };  
};

int main() {
    int val = TryMe::arr[0];
    return val;
}

我用clang得到一个未解析的外部符号。

TryMe::arr[0]是一个对象吗?如果是的话,它是否经常使用?

1 个答案:

答案 0 :(得分:8)

TryMe::arrodr-used,但您未提供定义( see it live ):

constexpr int TryMe::arr[1];

为什么gccclang之间的结果不一致?这是因为在C ++ 11和C ++ 14草案标准(强调我的)中,odr违规不需要不相关:

  

每个程序都应包含每个非内联的一个定义   在该程序中使用的函数或变量; 没有诊断   需要

我们可以看到它在C ++ 11标准草案3.2部分中使用了更多信息,其中说:

  

表达式可能会被评估,除非它是未评估的   操作数(第5条)或其子表达式。一个名称的变量   似乎是一种可能被评估的表达式,除非它被使用   满足出现在常量中的要求的对象   表达式(5.19)和左值到右值的转换(4.1)是   立即申请。

TryMe::arr是一个对象,它确实满足出现在常量表达式中的要求,但是左值到右值的转换不会立即应用于TryMe::arr,而是应用于TryMe::arr[0]。< / p>

C ++ 14标准草案中更新的措辞,适用于C ++ 11,因为它是通过缺陷报告( DR 712 )应用的:

  

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

表达式TryMe::arr[0]潜在结果3.22中的条件为空,因此使用率较高。

注意:您需要根据9.4.2 [class.static.data] 部分提供类外的定义,其中说明了(强调我的) :

  

可以在类中声明文字类型的静态数据成员   使用constexpr说明符定义;如果是的话,其声明应   指定一个brace-or-equal-initializer,其中包含每个initializer子句   这是一个赋值表达式是一个常量表达式。 [注意:在   在这两种情况下,成员都可能出现在常量表达式中。 -结束   note] 如果成员仍然在命名空间范围内定义   在程序和命名空间范围定义中使用odr-used(3.2)   不得包含初始化程序

更新

T.C。指出defect report 1926将以下项目符号添加到3.2 [basic.def.odr]第2段:

  
      
  • 如果e是带有数组操作数的下标操作(5.2.1 [expr.sub]),则该集合包含该操作数。
  •   

这意味着下标一个数组不再是一个odr用途,所以OPs代码将在C ++ 1z中很好地形成,它看起来像C ++ 14,因为缺陷看起来像C ++ 14