2012-11-12 48 views
177

以下定义有区别吗?关于变量的const与constexpr

const  double PI = 3.141592653589793; 
constexpr double PI = 3.141592653589793; 

如果不是,哪种风格在C++ 11中是首选?

+2

超集:http://stackoverflow.com/questions/14116003/difference-between-constexpr-and-const –

回答

197
的执行时间不会减慢

我相信有区别。让我们重命名,以便我们可以更容易地谈论他们:

const  double PI1 = 3.141592653589793; 
constexpr double PI2 = 3.141592653589793; 

两个PI1PI2是不变的,这意味着你不能修改它们。但是只有PI2是编译时常量。它在在编译时被初始化。可以在编译时或运行时初始化PI1。此外,只有PI2可用于需要编译时常量的上下文中。例如:

constexpr double PI3 = PI1; // error 

但:

constexpr double PI3 = PI2; // ok 

和:

static_assert(PI1 == 3.141592653589793, ""); // error 

但:

static_assert(PI2 == 3.141592653589793, ""); // ok 

至于你应该使用它?使用符合您需求的任何一种。你想确保你有一个编译时间常量,可以在需要编译时常量的上下文中使用吗?您是否希望能够在运行时通过计算来初始化它?等

+39

你确定吗?因为'const int N = 10; char a [N];'工作,并且数组边界必须是编译时常量。 – fredoverflow

+9

就我写的例子而言,我确信(在发布前测试每个例子)。但是,我的编译器确实让我将'PI1'转换为编译时积分常量以用于数组,但不能用作非类型的积分模板参数。所以'PI1'到整型的编译时可转换性似乎对我来说有点小打小闹。 –

+0

@HowardHinnant:对于整数类型和非整型类型,左值到右值转换的规则是细微的不同的:(5.19(2)):一个整数或枚举类型的glvalue,它是指一个非易失性const对象初始化,用一个常量表达式进行初始化','对比'一个文字类型的glvalue,它是指用constexpr定义的非易失性对象,或者是指这样的对象的一个​​子对象。这与隐式转换为'int'不同,后者具有不同的规则。 – rici

58

这里没有什么区别,但是当你有一个具有构造函数的类型时它很重要。

struct S { 
    constexpr S(int); 
}; 

const S s0(0); 
constexpr S s1(1); 

s0是一个常量,但它不承诺在编译时初始化。 s1标记为constexpr,所以它是一个常量,因为S的构造函数也被标记为constexpr,它将在编译时初始化。

多属此事宜时,初始化在运行时会耗费时间和你想要把这项工作过到编译器,它也耗费时间,但已编译的程序

+3

我同意:我到达的结论是,'constexpr'将导致诊断应编译对象的时间计算是不可能的。不太清楚的是,如果参数被声明为“const”而不是“constexpr”,那么函数*期望*常量参数是否可以在编译时执行:即执行“constexpr int foo(S)”在编译时如果我调用'foo(s0)'? –

+4

@MatthieuM:我怀疑'foo(s0)'是否会在编译时执行,但您永远不知道:编译器是否允许执行此类优化。当然,gcc 4.7.2和clang 3.2都不允许我编译'constexpr a = foo(s0);' – rici

23

constexpr表示在编译过程中常数和已知值。
const表示一个只是常量的值;编译期间不需要强制。

int sz; 
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation 
std::array<int, sz> data1;   // error! same problem 

constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant 
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr 

注意const不会提供相同的保障为constexpr,因为常量 物体不需要与编译时已知值进行初始化。

int sz; 
const auto arraySize = sz;  // fine, arraySize is const copy of sz 
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation 

所有的constexpr对象都是const的,但并不是所有的const对象都是constexpr。

如果您希望编译器确保在需要编译时常量的上下文中使用的变量的值可以是 ,则要达到的工具是constexpr,而不是const。

+1

我喜欢你的解释很多..你可以请评论更多关于我们可能需要在现实生活场景中使用编译时间常量的情况。 –

+1

@MayukhSarkar简单谷歌_C++为什么constexpr_,例如http://stackoverflow.com/questions/4748083/when-should-you-use-constexpr-capability-in-c11 –

4

A constexpr符号常量必须给出一个在编译时已知的值。 例如:

constexpr int max = 100; 
void use(int n) 
{ 
    constexpr int c1 = max+7; // OK: c1 is 107 
    constexpr int c2 = n+7; // Error: we don’t know the value of c2 
    // ... 
} 

为了处理其中被初始化与未在编译时已知的值,而是在初始化之后从不改变“可变”的值, C++提供的恒定的第二形式的情况下( a const)。 例如:

constexpr int max = 100; 
void use(int n) 
{ 
    constexpr int c1 = max+7; // OK: c1 is 107 
    const int c2 = n+7; // OK, but don’t try to change the value of c2 
    // ... 
    c2 = 7; // error: c2 is a const 
} 

这种“常量变量”原因有两个非常普遍:

  1. C++ 98没有constexpr,所以人们用常量
  2. 列表项“变量”不是常量表达式(它们的值在编译时不知道),但在初始化本身非常有用之后不会更改值。
+10

也许你应该提到,你的答案中的文字是逐字从“编程:原理和实践使用C++“由Stroustrup – Aky