2012-11-12 116 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