一文總結(jié) C++ 常量表達(dá)式、constexpr 和 const

TLDR

修飾變量的時(shí)候,可以把 constexpr 對(duì)象當(dāng)作加強(qiáng)版的 const 對(duì)象:const 對(duì)象表明值不會(huì)改變,但不一定能夠在編譯期取得結(jié)果;constexpr 對(duì)象不僅值不會(huì)改變,而且保證能夠在編譯期取得結(jié)果。如果一個(gè) const 變量能夠在編譯期求值,將其改為 constexpr 能夠讓代碼更清晰易讀。

constexpr 函數(shù)可以把運(yùn)行期計(jì)算遷移至編譯期,使得程序運(yùn)行更快(但會(huì)增加編譯時(shí)間)。但如果 constexpr 函數(shù)中存在無(wú)法在編譯期求值的參數(shù),則 constexpr 函數(shù)和普通一樣在運(yùn)行時(shí)求值,此時(shí)的返回值不是常量表達(dá)式。

1. 常量表達(dá)式和 constexpr

C++11 中引入了 constexpr 關(guān)鍵字。constexpr 是 const expression 的縮寫(xiě),即常量表達(dá)式。

常量表達(dá)式是指值不會(huì)改變且編譯期可以得到結(jié)果的表達(dá)式。

1.1 特點(diǎn)

值不會(huì)改變(這一點(diǎn)和普通 const 一樣)

編譯期就能得到結(jié)果?。ㄆ胀?const 不一定保證)

1.2 使用場(chǎng)景

C++ 在一些場(chǎng)景下必須使用常量表達(dá)式,比如:

數(shù)組大小

整型模板實(shí)參(如 std::array<T, N> 的長(zhǎng)度參數(shù) N)

switch-case 中的 case 標(biāo)簽

枚舉量的值

對(duì)齊規(guī)格

1.3 常見(jiàn)的常量表達(dá)式

字面值(如 42)

用常量表達(dá)式初始化的 const 對(duì)象

一個(gè)對(duì)象(或表達(dá)式)是否是常量表達(dá)式取決于類型和初始值,如:

int i1 = 42;? ? ? ? ? // i1 不是常量表達(dá)式:初始值 42 是字面值,但 i1 不是 const 類型

const int i2 = i1;? ? // i2 不是常量表達(dá)式:初始值 i1 不是常量表達(dá)式

const int i3 = 42;? ? // i3 是常量表達(dá)式:用字面值 42 初始化的 const 對(duì)象

const int i4 = i3 + 1; // i4 是常量表達(dá)式:用常量表達(dá)式 i3 + 1 初始化的 const 對(duì)象

const int i5 = getValue(); // 如果 getValue() 是普通函數(shù),則 i5 值要到運(yùn)行時(shí)才能確定,則不是常量表達(dá)式

1.4 constexpr 變量

上面的例子可以看出,不能直接判斷一個(gè) const 對(duì)象是否是常量表達(dá)式:例如 i4 是否是常量表達(dá)式取決于 i3 是否是常量表達(dá)式,而 i4 又可能用來(lái)初始化其他常量表達(dá)式。在復(fù)雜的系統(tǒng)中,很難一眼看出某個(gè) const 對(duì)象是否是常量表達(dá)式。

C++11 允許把變量聲明為 constexpr 類型,此時(shí)編譯器會(huì)保證 constexpr 變量是常量表達(dá)式(否則編譯報(bào)錯(cuò))。換句話說(shuō),只要看到 constexpr 類型的變量,則一定能夠在編譯期取得結(jié)果,可以用在需要常量表達(dá)式的場(chǎng)景。

int i1 = 42;

constexpr int i2 = i1; // constexpr 變量 'i2' 必須由常量表達(dá)式初始化。不允許在常量表達(dá)式中讀取非 const 變量 'i1'

constexpr int i3 = 42; // i3 是常量表達(dá)式

constexpr int i4 = i3 + 1; // i4 是常量表達(dá)式

constexpr int i5 = getValue(); // 只有 getValue() 是 constexpr 函數(shù)時(shí)才可以,否則編譯報(bào)錯(cuò)

1.5 constexpr 函數(shù)

constexpr 函數(shù)是指能用于常量表達(dá)式的函數(shù)。

需要強(qiáng)調(diào)的是,constexpr 函數(shù)既能用于要求常量表達(dá)式/編譯期常量的語(yǔ)境,也可以作為普通函數(shù)使用。

注意:constexpr 函數(shù)不一定返回常量表達(dá)式!

只有 constexpr 的所有實(shí)參都是常量表達(dá)式/編譯期常量時(shí),constexpr 函數(shù)的結(jié)果才是常量表達(dá)式/編譯期常量。只要有一個(gè)參數(shù)在編譯期未知,那就和普通函數(shù)一樣,在運(yùn)行時(shí)計(jì)算。

constexpr int sum(int a, int b) {

? return a + b;

}

constexpr int i1 = 42;

constexpr int i2 = sum(i1, 52); // 所有參數(shù)都是常量表達(dá)式,sum 的結(jié)果也是常量表達(dá)式,在編譯期求值

int AddThree(int i) {

? return sum(i, 3); // i 不是常量表達(dá)式,此時(shí) sum 作為普通函數(shù)使用

}

為了能保證 constexpr 函數(shù)在編譯時(shí)能隨時(shí)展開(kāi)計(jì)算,constexpr 函數(shù)隱式內(nèi)聯(lián)。內(nèi)聯(lián)函數(shù)和 constexpr 函數(shù)不同于其他函數(shù),允許定義多次,但要保證所有的定義一致。正因如此,內(nèi)聯(lián)函數(shù)和 constexpr 函數(shù)一般定義在頭文件中。

constexpr 限制

因?yàn)樾枰诰幾g期求值,所以 constexpr 函數(shù)有一些限制:返回類型和所有形參的類型必須是字面值類型(literal type)。除了內(nèi)置類型,用戶自定義的類也可以是字面值類型,因?yàn)樗臉?gòu)造函數(shù)和成員函數(shù)也可以是 constexpr 函數(shù)。

C++11 中 constexpr 函數(shù)還有一些額外限制(C++14 沒(méi)有這些限制):

返回值類型不能是 void

函數(shù)體內(nèi)只能有且只有一條 return 語(yǔ)句(但可以用 ? : 三目運(yùn)算符和遞歸)

如果是類的成員函數(shù),則為隱式 const 成員函數(shù)

1.6 使用 constexpr 的好處

編譯器可以保證 constexpr 對(duì)象是常量表達(dá)式(能夠在編譯期取得結(jié)果),而 const 對(duì)象不能保證。如果一個(gè) const 變量能夠在編譯期求值,將其改為 constexpr 能夠讓代碼更清晰易讀

constexpr 函數(shù)可以把運(yùn)行期計(jì)算遷移至編譯期,使得程序運(yùn)行更快(但會(huì)增加編譯時(shí)間)

對(duì)于常量表達(dá)式(編譯期值已知),編譯器可以進(jìn)行更多優(yōu)化,比如放到只讀內(nèi)存中。但這并不是 constexpr 特有的,有的 const 變量也是常量表達(dá)式

1.7 小結(jié)

修飾對(duì)象的時(shí)候,可以把 constexpr 當(dāng)作加強(qiáng)版的 const:const 對(duì)象只表明值不會(huì)改變,不一定能夠在編譯期取得結(jié)果;constexpr 對(duì)象不僅值不會(huì)改變,而且保證能夠在編譯期取得結(jié)果

constexpr 函數(shù)既可以用于編譯期計(jì)算,也可以作為普通函數(shù)在運(yùn)行期使用

散熱風(fēng)扇https://www.uv-semi.com/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 總述 又來(lái)更新了,今天帶來(lái)的是nullptr空指針常量、constexpr(常量表達(dá)式)C++的兩個(gè)用法。Resu...
    良知猶存閱讀 602評(píng)論 0 0
  • 常量表達(dá)式 常量表達(dá)式是指不會(huì)改變且在編譯過(guò)程中就能得到計(jì)算結(jié)果的表達(dá)式,比如下面的10,value1 + 1,v...
    土豆吞噬者閱讀 1,095評(píng)論 0 0
  • 本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成,引用內(nèi)容的版權(quán)歸原始作者所有,僅限于學(xué)習(xí)研究使用,不得用于任何商業(yè)用途。 常...
    深紅的眼眸閱讀 1,596評(píng)論 0 0
  • 運(yùn)行時(shí)常量性與編譯時(shí)常量性 const還可以修飾函數(shù)參數(shù)、函數(shù)返回值、函數(shù)本身、類等。在不同的使用條件下,cons...
    i_need_job閱讀 620評(píng)論 0 0
  • 首先,常量表達(dá)式的概念:在編譯期就可以計(jì)算出結(jié)果的表達(dá)式那么為什么要用常量表達(dá)式呢,用常量表達(dá)式會(huì)有什么好處:1....
    丑角的晨歌閱讀 4,348評(píng)論 0 1

友情鏈接更多精彩內(nèi)容