首先,常量表達(dá)式的概念:在編譯期就可以計算出結(jié)果的表達(dá)式
那么為什么要用常量表達(dá)式呢,用常量表達(dá)式會有什么好處:
1.允許一些計算只在編譯時進行一次,而不是每次程序運行時;
2.編譯器可以進行尺度更大的優(yōu)化;
3.可以用在需求編譯期間常量的上下文,例如數(shù)組長度等;
使用constexpr修飾變量時:
const 變量的初始化可以延遲到運行時,而 constexpr 變量必須在編譯時進行初始化。
所有constexpr對象都是const的,但是不是所有的const對象都是constexpr的。
使用constexpr修飾函數(shù)時:
constexpr函數(shù)限制持有和返回的類型為字面值類型(literal type),本質(zhì)上就是一些在編譯期間可確定值的類型。在C++中,除了void之外的內(nèi)置類型都是字面值類型,不過用戶定義的類型也有可能是字面值類型,因為構(gòu)造函數(shù)和其他成員函數(shù)可能是constexpr的;
如果實參都是常量表達(dá)式的話,那么它可以在編譯時產(chǎn)生返回值;
其它情況下,常量表達(dá)式函數(shù)跟普通函數(shù)一樣,只有在運行時才能被調(diào)用,產(chǎn)生返回值;
對constexpr函數(shù)的基本要求:
- 常量表達(dá)式函數(shù)必須有返回值(不可以是void函數(shù))
- 常量表達(dá)式函數(shù)體中只能有一條語句,且該語句必須是return語句。(可以使用?:、遞歸)但不產(chǎn)生實際代碼的語句可以在常量表達(dá)式函數(shù)中使用,如static_assert,using,typedef等(這條規(guī)定在C++14中大幅放松)
- return語句中,不能使用非常量表達(dá)式的變量、函數(shù),且return的表達(dá)式也要是常量表達(dá)式
- 常量表達(dá)式函數(shù)在使用前,必須有定義。(普通函數(shù)在被調(diào)用前只要有函數(shù)聲明就夠了,不一定有定義)
常量構(gòu)造函數(shù)的要求:
- 成員變量只能通過初始化列表來初始化,函數(shù)體必須為空
- 初始化列表只能由常量表達(dá)式來賦值
常量成員函數(shù)的要求:
- 常量成員函數(shù)被隱式定義為const成員函數(shù),不可以通過常量成員函數(shù)去修改成員變量。也就是說,常量成員函數(shù)往往是所謂的getter函數(shù)。(c++14則不同,允許constexpr成員函數(shù)去修改成員變量)
- 常量成員函數(shù)不能是virtual的
在C++11與C++14的區(qū)別:
在C++11標(biāo)準(zhǔn)中,對于constexpr修飾的函數(shù)給了及其苛刻的限定條件:函數(shù)的返回值類型及所有形參的類型都是字面值類型,而且函數(shù)體內(nèi)必須有且只有一條return語句。
這個條件顯然是太苛刻了,以至于很多在constexpr的操作都要借助?:表達(dá)式,遞歸等辦法實現(xiàn)。
在C++14中,放寬了這一限定,只保留了“函數(shù)的返回值類型及所有形參的類型都是字面值類型”,也就是說,這些值都在編譯期能確定了就行。
constexpr與const的本質(zhì)區(qū)別
const主要用于表達(dá)“對接口的寫權(quán)限控制”,即“對于被const修飾的量名(例如const指針變量),不得通過它對所指對象作任何修改”。(但是可以通過其他接口修改該對象)。另外,把對象聲明為const也為編譯器提供了潛在的優(yōu)化可能。具體來說就是,如果把一個量聲明為const,并且沒有其他地方對該量作取址運算,那么編譯器通常(取決于編譯期實現(xiàn))會用該量的實際常量值直接替換掉代碼中所有引用該量的地方,而不用在最終編譯結(jié)果中生成對該量的存取指令。
constexpr的主要功能則是讓更多的運算可以在編譯期完成,并能保證表達(dá)式在語義上是類型安全的。(譯注:相比之下,C語言中#define只能提供簡單的文本替換,而不具任何類型檢查能力)。與const相比,被constexpr修飾的對象則強制要求其初始化表達(dá)式能夠在編譯期完成計算。之后所有引用該常量對象的地方,若非必要,一律用計算出來的常量值替換。
能否同時使用constexpr與const?
對于變量來講,一般情況下constexpr已經(jīng)包含了const的語義,所以沒必要同時使用;但是也有特殊情況:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
return 0;
}
在這里const和constexpr在修飾不同的東西,constexpr和const都必須要有。constexpr表示NP指針本身是常量表達(dá)式,而const表示指向的值是一個常量。去掉const之后無法編譯,因為不能用正常指針指向常量。
對于成員函數(shù)來講,在C++11中constexpr同樣包含const的含義,但是C++14中則不,所以C++14中可能會需要同時使用const與constexpr。