C ++为什么我可以在类定义中初始化静态const char而不是静态const double?

时间:2016-02-01 21:47:56

标签: c++ c++11 static-members constexpr

以下是两行代码:

static const double RYDBERG_CONST_EV = 13.6056953;
static const char CHAR_H_EDGE = '-';

第二行编译没有错误,第一行不编译。 (错误:'constexpr' needed for in-class initialization of static data member...

解决方案显然是在类型之前添加关键字constexpr。这是必需的,因为double不是“整数类型”。但是为什么整数和浮点类型之间的行为不同?

3 个答案:

答案 0 :(得分:14)

我不相信这是有充分理由的,除非它在历史上有所增长。

在C ++ 11之前,积分类型的例外是可取的,因为人们希望将它们用作数组大小。这与整数const蚂蚁被视为常量表达式的另一个例外相关。浮点类型不存在的异常。

const int    ni = 10;
const float  nf = 10.0f;
int numbers1[(unsigned) ni];  // perfectly fine in all versions of C++
int numbers2[(unsigned) nf];  // error in all versions of C++

当C ++ 11引入constexpr时,它可以执行const整数类型的特殊外壳可以做的任何事情。对于任何文字类型,它的工作方式相同。因此,给定一个优秀的工具,不需要将整数类型的现有规则扩展到浮点。

今天,整体类型的特殊外壳大多是早期较暗日的遗留物。它不能从语言中删除,因为这样做会破坏依赖于这种特殊外壳的现有代码,但是由于constexpr constexpr,通过添加更多将会完全不需要的例外情况,进一步使语言复杂化几乎没有什么收获。应该期望人们迁移到constexpr而不再担心旧的问题。我认为这是一个非常合理的决定,但你当然可以争辩说应该做出另一个决定。

附录

正如T.C.所评论的那样,有一个(非) - defect report关于这个问题,委员会确认行为不会被改变,人们应该开始使用{ {1}}。

  

<强> 1826。 const常量表达式中的浮点

     

栏目:5.20 [expr.const]状态:NAD发布者:Ville Voutilainen日期:2014-01-04

     

用常量初始化的const整数可用于常量表达式,但用常量初始化的const浮点变量不能。这是故意的,与C ++ 03兼容,同时鼓励constexpr的一致使用。然而,有些人发现这种区别是令人惊讶的。

     

还观察到允许const浮点变量作为常量表达式将是ABI突破性变化,因为它会影响lambda捕获。

     

一种可能性可能是在常量表达式中弃用const个积分变量。

     

附加说明,2015年4月:

     

EWG要求CWG允许在常量表达式中使用const个浮点变量。

     

理由(2015年5月):

     

CWG认为当前的规则不应该改变,希望浮点值参与常量表达式的程序员应该使用constexpr而不是const

答案 1 :(得分:2)

对于措辞,§[class.static.data] / 3说:

  
      
  1. 如果非易失性const静态数据成员是整数或枚举类型,则在类中声明   definition 可以指定一个大括号或等于初始化程序,其中作为赋值表达式的每个initializer子句都是一个常量表达式(5.20)。 可以使用constexpr说明符在类定义中声明文字类型的静态数据成员;如果是这样,它的声明应该指定一个大括号或者相等的初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式。
  2.   

(emph mine)。请注意,在整数类型的情况下,静态数据成员可以,而不是必须,具有初始化(您始终可以将其置于类定义之外)。另外,在类定义中使用初始化的唯一方法是通过constexpr。

关于允许在类定义中初始化整数类型(也在C ++ 98中)的推理(恕我直言)是为了实现这样的非常简单的模式:

class Foo {
    static const size_t arrayLen = 42;
    int foo[arrayLen];
};
没有体内初始化的

将无法实现。

答案 2 :(得分:0)

众所周知:

  • static const整数类型成员可以在类定义中初始化。

  • static constexpr成员可以在课程定义中初始化

double不是整数类型,应标记为constexpr

机器中生成的可执行文件可以在浮点表示计算不同的其他机器上运行。 Integral Constant Expressions不要改变。

标记一个对象static表示所有观察者都可以知道它,并且使const表示该值不会改变。编译器可以生成一个值(例如314)并将其放入只读部分,因为范围是在标准中定义的。

另一方面,double不在标准中,并且在类定义中不能进行远程检查和在编译时存储的值。人们可能很容易得到不同的目标文件,其中的对象具有不同的static const double值,从而破坏了ODR。

这是一个简单的例子:

struct foo
{
static char const a = 1/11; // everyone gets 0 at compile-time
};

你会说,但这可能发生在双打和初看,就像这样

struct foo
{
static double const y=1.0/11.0; // the true value is 0.090909... 
};

似乎是可验证的,但在一台机器中双重表示在另一个0.09091中将为0.090909091

使用constexpr允许向编译器说明在编译时可以获得验证这一点所需的输入。但是,实际评估可以在运行时进行。

由于C ++编译器生成的目标文件可以移动到具有不同浮点表示的机器,因此必须告知必须在编译期间进行此检查以确保一致性。

问题是XY-problem的典型示例。而不是问,“为什么我必须用constexpr标记任何内容?”给出了一个谜题char - vs - float。现在的问题是,“为什么我们必须将constexpr用于非整数类型?”和here you can find your answer