C++關(guān)鍵字constexpr和consteval的注意事項(xiàng)及說明
C++ 支持兩種不可變性概念(即狀態(tài)不可變的對象)
const
- 其大致含義是“我承諾不會更改此值”。
- 它主要用于定義接口,以便在通過指針和引用將數(shù)據(jù)傳遞給函數(shù)時,無需擔(dān)心數(shù)據(jù)會被修改。
- 編譯器會強(qiáng)制執(zhí)行由 const 所作的這一承諾。const 變量的值可以在運(yùn)行時計(jì)算得出。
constexpr
- 其大致含義是“在編譯時進(jìn)行求值”。
- 它主要用于定義常量,以便將數(shù)據(jù)存放在只讀內(nèi)存中(從而降低數(shù)據(jù)被破壞的風(fēng)險(xiǎn)),同時也旨在提升性能。constexpr 變量的值必須由編譯器在編譯時計(jì)算得出。
例如:
constexpr int dmv = 17; // dmv 是一個命名常量
int var = 17; // var 不是一個常量
const double sqv = sqrt(var); // sqv 是一個命名常量,可能在運(yùn)行時計(jì)算
double sum(const vector<double>&); // sum 不會修改其參數(shù)值
vector<double> v{ 1.2, 3.4, 4.5 }; // v 不是一個常量
const double s1 = sum(v); // 可行: sum(v) 在運(yùn)行時計(jì)算
constexpr double s2 = sum(v); // 錯誤: sum(v) 不是一個常量表達(dá)式若要使函數(shù)可在常量表達(dá)式中使用(即在由編譯器進(jìn)行求值的表達(dá)式中),該函數(shù)必須定義為 constexpr 或 consteval
例如:
constexpr double square(double x) { return x*x; }
constexpr double max1 = 1.4*square(17); // 可行: 1.4*square(17) 是一個常量表達(dá)式,編譯時計(jì)算
constexpr double max2 = 1.4*square(var); // 錯誤: var 不是一個常量, 因此square(var) 不是一個常量,無法在編譯時進(jìn)行計(jì)算
const double max3 = 1.4*square(var); // 可行: 可以在運(yùn)行時計(jì)算constexpr 函數(shù)可以接受非常量實(shí)參,但在這種情況下,其求值結(jié)果將不再是常量表達(dá)式。我們允許在不強(qiáng)制要求常量表達(dá)式的語境中,調(diào)用帶有非常量表達(dá)式實(shí)參的 constexpr 函數(shù)。這樣一來,我們便無需重復(fù)定義本質(zhì)上完全相同的函數(shù)——即無需分別為常量表達(dá)式和變量各定義一個版本。若我們希望某個函數(shù)僅用于編譯期求值,則應(yīng)將其聲明為 consteval,而非 constexpr。例如:
consteval double square2(double x) { return x*x; }
constexpr double max1 = 1.4*square2(17); // 可行: 1.4*square(17) 是一個常量表達(dá)式
const double max3 = 1.4*square2(var); // 錯誤: var 的定義不是一個常量而是變量聲明為 constexpr 或 consteval 的函數(shù),是 C++ 對“純函數(shù)(pure functions)”這一概念的實(shí)現(xiàn)。它們不得產(chǎn)生副作用,且只能通過參數(shù)傳遞給它們的信息。
具體而言,它們不能修改非局部變量,但允許包含循環(huán)結(jié)構(gòu)并使用自身的局部變量。
例如:
constexpr double nth(double x, int n) // 假設(shè) 0<=n
{
double res = 1;
int i = 0;
while (i<n) { // while循環(huán): 條件為真則執(zhí)行
res *= x;
++i;
}
return res;
}在某些語境下,語言規(guī)則強(qiáng)制要求使用常量表達(dá)式(例如:數(shù)組邊界 (§1.7)、case 標(biāo)簽 (§1.8)、模板值實(shí)參 (§7.2),以及使用 constexpr 聲明的常量)。而在其他情況下,編譯期求值對于提升性能至關(guān)重要。即便暫不考慮性能因素,不可變性(即對象處于一種不可更改的狀態(tài))這一概念本身也是一個重要的設(shè)計(jì)考量。
注意:
consteval 是 C++20 新增的一個關(guān)鍵字,其旨在強(qiáng)制函數(shù)編譯時求值(即將函數(shù)聲明為一個“即時”函數(shù)),且只能用于函數(shù)或函數(shù)模板,其調(diào)用參數(shù)必須是常量,不能是變量,是對 constexpr 的進(jìn)一步限制。
例如:
consteval int sqr(int n)
{
return n * n; //調(diào)用時參數(shù)必須是常量
}
constexpr int r = sqr(100); // 可行:編譯時計(jì)算,參數(shù)是常量
int x = 100;
int r2 = sqr(x); // 錯誤: 調(diào)用不會產(chǎn)生一個常量,參數(shù)是變量
const int x = 100; //可行:參數(shù)是常量
int r2 = sqr(x);
constexpr int r3 = sqr(x);
const int r4 = sqr(x);
consteval int sqrsqr(int n)
{
return sqr(sqr(n)); // 這時不是一個常量表達(dá)式, 但可行,因?yàn)檎{(diào)用者是 consteval 函數(shù)
}
constexpr int dblsqr(int n)
{
return 2 * sqr(n); // 錯誤: 其外圍函數(shù)不是一個 consteval
// 且 sqr(n) 不是一常量,無法在編譯時進(jìn)行計(jì)算
}
consteval int f() { return 42; } //可行
consteval auto g() { return &f; }
consteval int h(int (*p)() = g()) { return p(); }
constexpr int r = h(); // 可行
constexpr auto e = g(); // 格式錯誤:一個立即函數(shù)指針不允許作為一個常量表達(dá)式結(jié)果總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解C/C++中const關(guān)鍵字的用法及其與宏常量的比較
簡單的說const關(guān)鍵字修飾的變量具有常屬性,也就是說它所修飾的變量不能被修改,下文給大家介紹C/C++中const關(guān)鍵字的用法及其與宏常量的比較,需要的朋友可以參考下2017-07-07
C/C++寬窄字符轉(zhuǎn)換與輸出的多種實(shí)現(xiàn)方法
本文主要介紹了C/C++寬窄字符轉(zhuǎn)換與輸出的多種實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08

