天天看點

關于constexpr與const

C++之父是這樣解釋二者的:

const:大緻意思是說我承諾不改變這個值,主要用于說明接口,這樣變量傳遞給函數就不擔心變量會在函數内被修改了編譯器負責确認并執行const的承諾。

constexpr:大緻意思是在編譯時求值,主要用于說明常量,作用是允許資料置于隻讀記憶體以及提升性能。

按照這種說法,我的了解是const大多用于接口中,聲明不對傳入的參數做修改,而constexpr多用于編譯時求值,需要編譯時求值的大概就是數組邊界聲明(數組大小)、case标簽、某些模版實參及使用constexpr的常量(cpp程式設計語言第四版-p37)

對于修飾Object來說,

const并未區分出編譯期常量和運作期常量

constexpr限定在了編譯期常量

基本含義/文法

const和constexpr都可以來修飾對象和函數。

修飾對象的時候兩者之間最基本的差別是:

const修飾一個對象表示它是常量。這暗示對象一經初始化就不會再變動了,并且允許編譯器使用這個特點優化程式。這也防止程式員修改了本不應該修改的對象。

constexpr是修飾一個常量表達式。但請注意constexpr不是修飾常量表達式的唯一途徑。

修飾函數的時候兩者之間最基本的差別是:

1.const隻能用于非靜态成員的函數(靜态成員函數并不包含this指針,也就不存在const來修飾他了)而不是所有函數。它保證成員函數不修改任何非靜态資料。

2.constexpr可以用于含參和無參函數。constexpr函數适用于常量表達式,隻有在下面的情況下編譯器才會接受constexpr函數:

a.函數體必須足夠簡單,除了typedef和靜态元素,隻允許有return語句。如構造函數隻能有初始化清單,typedef和靜态元素 (實際上在C++14标準中已經允許定義語句存在于constexpr函數體内了)

b.參數和傳回值必須是字面值類型

常量表達式

常量表達式的概念如下

必須是可以在編譯階段被識别的。比如模版的參數/數組的大小。

template <int N>
class fixed_size_list
{ /*...*/ };

fixed_size_list<X> mylist;     //X必須是字面值類型

int numbers[X];   //  X必須是字面值類型
           

但是注意下面兩點

用constexpr修飾某物并不保證它一定在編譯時被計算,也可以在運作時被計算。

不用constexpr也可能是一個常量表達式,如

int main()
{
const int N = ;
int num[N] = {,,,};//N是一個常量表達式
}
//N在聲明時初始化,滿足常量表達式的标準,雖然沒用constexpr
           

是以到底什麼時候用constexpr?

像上面的N,雖然沒有用 constexpr 仍然是一個常量表達式。事實上,const本身和它的枚舉類型若在聲明時初始化那麼就是一個常量表達式。

在函數中若有常量表達式那麼必須用constexpr,僅僅滿足常量表達式的條件是不夠的,如

template <int N>
class list{ };

constexpr int sqr1(int arg)
{ return arg*arg; }

int sqr2(int arg)
{ return arg*arg; }

int main()
{
const int X = ;

list<sqr1(X)> mylist1;//可以,因為sqr1時constexpr函數
list<sqr2(X)> mylist2;//不可以,因為sqr2不是constexpr函數
return ;
}
           

什麼時候該同時使用兩者?

在修飾變量的時候

修飾變量時沒有必要同時使用const和constexpr 因為constexpr包含了 const的含義

constexpr const int N = ;
constexpr int N = ;
//兩行的意思完全相同
           

然而注意有一些情況const和constexpr在修飾不同的東西,比如

static constexpr int N = ;
int main()
{
    constexpr const int *NP = &N
    return ;
}
           

在這裡constexpr和const都必須要有。constexpr表示NP指針本身是常量表達式,而const表示指向的值是一個常量。去掉const之後無法編譯,因為不能用普通指針指向常量。

在修飾成員函數的時候

在C++11中,對成員函數而言constexpr同樣包含const的含義。然而在C++14中可能已經改變了。如

constexpr void f();
           

以後可能必須寫成

constexpr void f() const;
           

雖然目前寫成const仍然有效,但最好使用constexpr來防止以後修改大量代碼的可能性。