欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中關(guān)鍵字constexpr的實現(xiàn)示例

 更新時間:2025年11月11日 10:08:09   作者:MzKyle  
constexpr是C++中用于編譯期計算的關(guān)鍵詞,它允許在編譯期確定值并進行安全檢查,從而提高編譯效率和代碼的健壯性,本文主要介紹了C++中關(guān)鍵字constexpr的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下

constexpr 是 C++11 引入并在后續(xù)標準(C++14/C++17/C++20)中持續(xù)增強的關(guān)鍵字,其核心作用是在編譯期計算常量或表達式,既保證了編譯期的安全性檢查,又能消除運行期計算的開銷,是實現(xiàn)“零成本抽象”和編譯期元編程的關(guān)鍵技術(shù)。

一、constexpr 的本質(zhì)與核心目標

constexpr 的字面意思是“常量表達式(constant expression)”,它的設(shè)計目標有兩個核心:

  1. 編譯期確定值:讓變量、函數(shù)或?qū)ο蟮娜≈翟诰幾g階段就能計算完成,避免運行時的冗余計算(如重復(fù)的數(shù)學(xué)運算、常量初始化)。
  2. 強類型安全檢查:強制編譯器驗證“是否滿足編譯期計算條件”,若存在運行時依賴(如動態(tài)輸入、未初始化變量),則直接報錯,避免潛在的邏輯錯誤。

從本質(zhì)上看,constexpr 是對“常量”概念的強化——它不僅要求值“不可修改”,更要求值“可在編譯期確定”,這是它與傳統(tǒng) const 最核心的區(qū)別。

二、constexpr 變量:編譯期初始化的常量

constexpr 最基礎(chǔ)的用法是修飾變量,要求變量在編譯期完成初始化,且后續(xù)不可修改。

1. 變量聲明的核心要求

  • 必須在聲明時初始化,且初始化表達式必須是常量表達式(即無運行時依賴的表達式)。
  • 變量類型必須是“字面類型(Literal Type)”——即能通過 constexpr 構(gòu)造函數(shù)初始化、無虛函數(shù)/虛基類、成員均為字面類型的類型(如 intdouble、數(shù)組、滿足條件的自定義類)。

正確示例

// 1. 基本類型:編譯期計算 3+2 的結(jié)果(值為5)
constexpr int a = 3 + 2;
// 2. 數(shù)組:大小由 constexpr 變量確定(編譯期已知)
constexpr size_t arr_size = 10;
int arr[arr_size]; // 合法,數(shù)組大小編譯期確定
// 3. 常量表達式嵌套:依賴其他 constexpr 變量
constexpr int b = a * 4; // 編譯期計算 5*4=20

錯誤示例

int x = 5;
// 錯誤:初始化表達式依賴運行時變量 x(非常量表達式)
constexpr int c = x + 3; 
// 錯誤:未初始化(constexpr 變量必須聲明時初始化)
constexpr double d; 

2. 修飾指針與引用的特殊規(guī)則

constexpr 修飾指針/引用時,需明確“修飾的是指針本身”還是“指向的對象”,規(guī)則與 const 類似,但要求更嚴格(必須編譯期確定地址):

  • constexpr 指針:指針本身是編譯期常量(地址固定),指向的對象是否可修改需額外用 const 聲明。
    int num = 10;
    // 錯誤:num 是棧上變量(地址運行時確定),無法作為 constexpr 指針的目標
    constexpr int* p1 = # 
    
    // 正確:全局變量地址編譯期確定,p2 是 constexpr 指針(地址固定)
    int global_num = 20;
    constexpr int* p2 = &global_num; 
    // 正確:constexpr 指針 + const 對象(指針地址固定,指向的內(nèi)容不可改)
    constexpr const int* p3 = &global_num; 
    
  • constexpr 引用:引用的目標必須是編譯期常量(地址固定),且引用本身不可重新綁定(與 const 引用一致,但要求更高)。
    // 正確:引用目標是 constexpr 變量(編譯期常量)
    constexpr int e = 5;
    constexpr const int& ref = e; 
    

三、constexpr 函數(shù):編譯期可執(zhí)行的函數(shù)

constexpr 函數(shù)是支持“編譯期調(diào)用”的函數(shù)——當(dāng)函數(shù)的實參是常量表達式時,函數(shù)會在編譯期計算結(jié)果;若實參是運行時變量,則退化為普通函數(shù)在運行期執(zhí)行(即“兩態(tài)性”)。

const修飾的函數(shù)(修飾函數(shù)返回值或者函數(shù)類型)不可以因為constexpr的存才而刪除,起到的作用不同,constexpr修飾作用可退回普通函數(shù),但是const修飾的函數(shù)必定是常函數(shù)。

1. 函數(shù)聲明的核心要求(隨標準演進放寬)

constexpr 函數(shù)的限制在 C++11 到 C++20 中逐步放寬,核心要求如下:

標準版本核心限制允許的操作
C++111. 函數(shù)體僅允許 return 語句
2. 不能有局部變量/循環(huán)
3. 返回值和參數(shù)必須是字面類型
僅常量表達式計算、return
C++141. 允許定義局部變量(需是字面類型,可初始化)
2. 允許循環(huán)(for/while)
3. 允許條件判斷(if/else)
局部變量、循環(huán)、條件判斷、常量計算
C++171. 允許 constexpr lambda(嵌套使用)
2. 允許使用部分標準庫函數(shù)(如 std::string_view)
lambda、部分標準庫調(diào)用
C++201. 允許動態(tài)內(nèi)存分配(new/delete,但需在編譯期釋放)
2. 允許使用 std::vector/std::string(部分實現(xiàn))
3. 允許 try-catch(僅編譯期異常)
動態(tài)內(nèi)存(編譯期釋放)、復(fù)雜容器、異常處理

2. 典型示例:編譯期計算階乘

// C++14 及以上:constexpr 函數(shù)支持循環(huán)
constexpr int factorial(int n) {
    if (n < 0) throw "n must be non-negative"; // C++20 允許 try-catch
    int result = 1;
    for (int i = 1; i <= n; ++i) {
        result *= i;
    }
    return result;
}

// 1. 編譯期調(diào)用:實參是常量表達式(5),結(jié)果在編譯期計算為 120
constexpr int f5 = factorial(5); 
// 2. 運行期調(diào)用:實參是運行時變量(x),結(jié)果在運行期計算
int x = 6;
int f6 = factorial(x); 

3. 關(guān)鍵特性:兩態(tài)性與編譯期驗證

  • 兩態(tài)性:constexpr 函數(shù)并非“必須編譯期執(zhí)行”,而是“可編譯期執(zhí)行”。實參是常量表達式時編譯期計算,否則運行期計算,兼顧靈活性與性能。
  • 編譯期驗證:若強制要求函數(shù)在編譯期執(zhí)行(如賦值給 constexpr 變量),編譯器會嚴格檢查——若函數(shù)存在無法編譯期執(zhí)行的操作(如依賴運行時輸入),則直接報錯。

四、constexpr 類與對象:編譯期構(gòu)造的自定義類型

C++11 允許類通過 constexpr 構(gòu)造函數(shù) 創(chuàng)建“編譯期對象”,即對象的所有成員在編譯期初始化,且對象的成員函數(shù)可通過 constexpr 修飾實現(xiàn)編譯期調(diào)用。

1. constexpr 構(gòu)造函數(shù)的要求

  • 必須初始化類的所有非靜態(tài)成員(確保無未初始化成員)。
  • C++11 中函數(shù)體必須為空(僅通過初始化列表初始化);C++14 及以上允許簡單函數(shù)體(如條件判斷)。
  • 構(gòu)造函數(shù)的參數(shù)必須是字面類型。

示例:編譯期可構(gòu)造的 Point 類

class Point {
private:
    int x_, y_;
public:
    // C++11 風(fēng)格:空函數(shù)體,通過初始化列表初始化成員
    constexpr Point(int x, int y) : x_(x), y_(y) {}
    
    // constexpr 成員函數(shù):編譯期計算兩點距離的平方
    constexpr int distance_sq(const Point& other) const {
        int dx = x_ - other.x_;
        int dy = y_ - other.y_;
        return dx*dx + dy*dy;
    }
    
    // 普通成員函數(shù):僅運行期調(diào)用
    void print() const {
        std::cout << "(" << x_ << "," << y_ << ")\n";
    }
};

// 1. 編譯期創(chuàng)建對象:構(gòu)造函數(shù)實參是常量表達式
constexpr Point p1(1, 2);
constexpr Point p2(4, 6);
// 2. 編譯期調(diào)用成員函數(shù):計算距離平方(結(jié)果 25)
constexpr int dist_sq = p1.distance_sq(p2); 
// 3. 運行期調(diào)用普通成員函數(shù)
p1.print(); 

2. constexpr 對象的特性

  • constexpr 對象的所有非靜態(tài)成員均為編譯期常量,可直接用于常量表達式(如作為 constexpr 函數(shù)的實參)。
  • constexpr 對象的 this 指針在編譯期可見,因此其 constexpr 成員函數(shù)可直接訪問成員并完成編譯期計算。

五、C++17/C++20 關(guān)鍵增強:constexpr lambda、consteval 與 constinit

隨著標準演進,constexpr 的能力大幅擴展

1. C++17:constexpr lambda

C++17 允許 lambda 表達式通過 constexpr 修飾(或隱式滿足 constexpr 條件),使其可在編譯期執(zhí)行。

示例:編譯期使用 lambda 計算數(shù)組總和

#include <array>

constexpr auto sum_array = [](const auto& arr) {
    int sum = 0;
    for (auto val : arr) {
        sum += val;
    }
    return sum;
};

// 編譯期計算數(shù)組總和:sum = 1+2+3+4+5 = 15
constexpr std::array<int, 5> arr = {1,2,3,4,5};
constexpr int total = sum_array(arr); 

2. C++20:consteval 與 constinit

C++20 新增兩個關(guān)鍵字,進一步細化“編譯期計算”的語義,與 constexpr 形成互補:

  • consteval:強制函數(shù)“必須在編譯期執(zhí)行”(即“立即函數(shù)”),若無法編譯期計算(如實參是運行時變量),直接報錯。
    // consteval 函數(shù):必須編譯期執(zhí)行
    consteval int square(int n) {
        return n * n;
    }
    
    constexpr int s4 = square(4); // 正確:編譯期計算(16)
    int y = 5;
    // 錯誤:實參 y 是運行時變量,無法編譯期執(zhí)行
    int s5 = square(y); 
    
  • constinit:確保變量“在編譯期初始化”(僅適用于靜態(tài)/線程局部變量),但不要求變量是“常量”(即后續(xù)可修改,只要初始化在編譯期完成)。
    // 錯誤:靜態(tài)變量默認運行時初始化(全局變量除外)
    static int static_num = 10; 
    // 正確:constinit 強制靜態(tài)變量編譯期初始化(值 20)
    constinit static int constinit_num = 20; 
    constinit_num = 30; // 合法:constinit 僅限制初始化,不限制后續(xù)修改
    

constexpr、consteval、constinit 對比

關(guān)鍵字核心語義是否允許運行期執(zhí)行適用場景
constexpr可編譯期執(zhí)行(兩態(tài)性)是(實參為運行時變量時)兼顧編譯期計算與運行期靈活調(diào)用
consteval必須編譯期執(zhí)行(強制)否(否則報錯)確保零運行時開銷(如編譯期哈希)
constinit強制編譯期初始化是(變量可后續(xù)修改)靜態(tài)變量的編譯期初始化(如全局配置)

六、constexpr 的核心應(yīng)用場景

constexpr 并非“語法糖”,而是解決實際問題的工具,核心應(yīng)用場景包括:

1. 編譯期計算:消除運行時開銷

對于固定邏輯(如數(shù)學(xué)公式、常量配置),通過 constexpr 在編譯期計算結(jié)果,避免運行時重復(fù)計算。例如:

  • 編譯期計算數(shù)組大小(替代 sizeof(arr)/sizeof(arr[0]))。
  • 編譯期生成哈希值(如字符串字面量的哈希,避免運行時哈希計算)。

2. 靜態(tài)斷言(static_assert):編譯期合法性檢查

static_assert 的條件必須是常量表達式,constexpr 可提供復(fù)雜的編譯期條件判斷,實現(xiàn)更靈活的斷言。例如:

// 編譯期檢查模板參數(shù)是否為偶數(shù)
template <int N>
void process() {
    static_assert(N % 2 == 0, "N must be even"); // 條件依賴 constexpr 計算
}

process<4>(); // 正確:4 是偶數(shù)
// process<5>(); // 錯誤:編譯期斷言失敗,提示 "N must be even"

3. 編譯期元編程:生成代碼邏輯

結(jié)合模板與 constexpr,可在編譯期生成代碼(如循環(huán)展開、類型判斷),實現(xiàn)“元編程”。例如:

  • 編譯期遍歷數(shù)組并計算結(jié)果(無需運行時循環(huán))。
  • 編譯期根據(jù)類型生成不同的處理邏輯(替代運行時 if-else)。

4. 常量表達式接口:增強類型安全

通過 constexpr 定義接口(如 constexpr 函數(shù)、constexpr 類),強制調(diào)用者使用編譯期常量,避免運行時錯誤。例如:

  • 自定義數(shù)值類型(如角度、長度),通過 constexpr 構(gòu)造函數(shù)確保輸入合法(如角度范圍 0-360)。

七、常見誤區(qū)與注意事項

  1. “constexpr 變量一定在編譯期存儲”:錯誤。constexpr 僅要求“值在編譯期確定”,存儲位置仍由編譯器決定(如可能存儲在數(shù)據(jù)段,也可能直接內(nèi)聯(lián)到代碼中)。
  2. “constexpr 函數(shù)只能返回常量”:錯誤。constexpr 函數(shù)的返回值是否為常量,取決于實參——實參是常量表達式時返回常量,實參是運行時變量時返回普通值。
  3. “constexpr 與 const 完全等價”:錯誤。const 僅表示“值不可修改”,不要求“值在編譯期確定”(如 const int a = rand(); 是合法的,但 constexpr int a = rand(); 是錯誤的);而 constexpr 同時要求“不可修改”和“編譯期確定”。
  4. “C++20 后 constexpr 可隨意使用動態(tài)內(nèi)存”:錯誤。C++20 允許 constexpr 函數(shù)使用 new,但必須在編譯期通過 delete 釋放(否則編譯器報錯),無法將動態(tài)內(nèi)存泄露到運行時。

補充const與constexpr

constconstexpr 修飾函數(shù)時的作用和場景完全不同,核心區(qū)別在于:const 關(guān)注函數(shù)是否修改對象狀態(tài)(僅用于成員函數(shù)),而 constexpr 關(guān)注函數(shù)是否能在編譯時求值(可用于任意函數(shù))。

1.const修飾函數(shù)(僅適用于類的非靜態(tài)成員函數(shù))

  • 作用:聲明該成員函數(shù)是“常量成員函數(shù)”,承諾不會修改對象的非靜態(tài)數(shù)據(jù)成員,也不能調(diào)用非 const 的成員函數(shù)(防止間接修改對象)。
    本質(zhì)是對函數(shù)的“行為約束”,確保調(diào)用該函數(shù)時對象狀態(tài)不變,屬于運行時的類型安全保障。

  • 語法const 放在函數(shù)參數(shù)列表后(const 成員函數(shù)的標志)。

    class A {
    private:
        int x;
    public:
        // const 成員函數(shù):承諾不修改 x,也不能調(diào)用非 const 函數(shù)
        int getX() const { 
            // x = 10;  // 編譯錯誤:const 函數(shù)不能修改成員
            return x; 
        }
    
        void setX(int val) {  // 非 const 函數(shù):可以修改成員
            x = val; 
        }
    };
    
  • 適用場景
    當(dāng)需要獲取對象狀態(tài)(如訪問器 getter)但不修改它時,用 const 修飾,確保函數(shù)的“只讀”行為。
    例如:const A a; a.getX(); 合法(const 對象只能調(diào)用 const 成員函數(shù)),但 a.setX(5); 會報錯。

2.constexpr修飾函數(shù)(適用于任意函數(shù):普通函數(shù)、成員函數(shù)、構(gòu)造函數(shù)等)

  • 作用:聲明該函數(shù)是“常量表達式函數(shù)”,可以在編譯時被求值(前提是輸入?yún)?shù)為常量表達式)。
    本質(zhì)是對函數(shù)的“計算時機約束”,允許函數(shù)結(jié)果作為編譯期常量使用(如模板參數(shù)、數(shù)組大小等),屬于編譯時的計算能力保障。

  • 語法constexpr 放在函數(shù)返回類型前。

    // 普通 constexpr 函數(shù):編譯時可求值
    constexpr int add(int a, int b) {
        return a + b;
    }
    
    class B {
    private:
        int y;
    public:
        // constexpr 構(gòu)造函數(shù):允許創(chuàng)建編譯期對象
        constexpr B(int val) : y(val) {}
    
        // constexpr 成員函數(shù):編譯時可求值(需滿足條件)
        constexpr int getY() const {  // 可同時是 const(雙重約束)
            return y;
        }
    };
    
  • 適用場景
    當(dāng)需要在編譯時計算結(jié)果(如常量、模板參數(shù))時,用 constexpr 修飾。例如:

    constexpr int sum = add(3, 5);  // 編譯時計算,sum 是編譯期常量(8)
    constexpr B b(10);             // 編譯期創(chuàng)建對象
    int arr[b.getY()];             // 合法:數(shù)組大小是編譯期常量(10)
    

    注意:constexpr 函數(shù)并非只能在編譯時調(diào)用,當(dāng)輸入?yún)?shù)是運行時變量時,它也能像普通函數(shù)一樣在運行時調(diào)用。

3. 核心對比表

維度const 修飾函數(shù)constexpr 修飾函數(shù)
適用范圍僅類的非靜態(tài)成員函數(shù)任意函數(shù)(普通函數(shù)、成員函數(shù)、構(gòu)造函數(shù)等)
核心作用保證函數(shù)不修改對象狀態(tài)(只讀約束)保證函數(shù)可在編譯時求值(編譯期計算)
本質(zhì)運行時的對象狀態(tài)保護編譯時的計算能力支持
與常量表達式的關(guān)系無關(guān)(結(jié)果不能直接作為編譯期常量)直接相關(guān)(結(jié)果可作為編譯期常量)
能否同時使用可以(constexpr const 成員函數(shù),雙重約束)無沖突,constexpr 不影響 const 的作用
  • const 修飾成員函數(shù):告訴編譯器和使用者“這個函數(shù)不會改對象,放心在 const 對象上調(diào)用”。
  • constexpr 修飾函數(shù):告訴編譯器“這個函數(shù)可以在編譯時算,給我編譯期優(yōu)化的能力”。
  • 兩者可以共存(如 constexpr const 成員函數(shù)),此時函數(shù)既保證不修改對象,又能在編譯時求值。

到此這篇關(guān)于C++中關(guān)鍵字constexpr的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)C++ 關(guān)鍵字constexpr內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • C語言 實現(xiàn)歸并排序算法

    C語言 實現(xiàn)歸并排序算法

    這篇文章主要介紹了C語言 實現(xiàn)歸并排序算法的相關(guān)資料,需要的朋友可以參考下
    2016-11-11
  • 一篇文章帶你了解C++智能指針詳解

    一篇文章帶你了解C++智能指針詳解

    這篇文章主要介紹了c++ 智能指針基礎(chǔ)的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下,希望能給你帶來幫助
    2021-08-08
  • 詳細分析C++ 多態(tài)和虛函數(shù)

    詳細分析C++ 多態(tài)和虛函數(shù)

    這篇文章主要介紹了C++ 多態(tài)和虛函數(shù)的相關(guān)資料,文中示例代碼非常詳細,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C++使用一個棧實現(xiàn)另一個棧的排序算法示例

    C++使用一個棧實現(xiàn)另一個棧的排序算法示例

    這篇文章主要介紹了C++使用一個棧實現(xiàn)另一個棧的排序算法,結(jié)合實例形式分析了C++借助輔助棧實現(xiàn)棧排序算法的相關(guān)操作技巧,需要的朋友可以參考下
    2017-05-05
  • C++中輸入輸出流及文件流操作總結(jié)

    C++中輸入輸出流及文件流操作總結(jié)

    這篇文章主要為大家總結(jié)了C++中輸入輸出流及文件流操作,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • C++詳細講解對象的構(gòu)造

    C++詳細講解對象的構(gòu)造

    當(dāng)在參數(shù)化構(gòu)造函數(shù)中聲明對象時,必須將初始值作為參數(shù)傳遞給構(gòu)造函數(shù)。對象聲明的常規(guī)方法可能不起作用。構(gòu)造函數(shù)可以顯式或隱式調(diào)用,讓我們一起了解對象的構(gòu)造
    2022-04-04
  • C++超詳細講解拷貝構(gòu)造函數(shù)

    C++超詳細講解拷貝構(gòu)造函數(shù)

    我們經(jīng)常會用一個變量去初始化一個同類型的變量,那么對于自定義的類型也應(yīng)該有類似的操作,那么創(chuàng)建對象時如何使用一個已經(jīng)存在的對象去創(chuàng)建另一個與之相同的對象呢
    2022-06-06
  • C++/Php/Python 語言執(zhí)行shell命令的方法(推薦)

    C++/Php/Python 語言執(zhí)行shell命令的方法(推薦)

    下面小編就為大家?guī)硪黄狢++/Php/Python 語言執(zhí)行shell命令的方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • C++編程中隊內(nèi)聯(lián)函數(shù)的理解和使用

    C++編程中隊內(nèi)聯(lián)函數(shù)的理解和使用

    這篇文章主要介紹了C++編程中隊內(nèi)聯(lián)函數(shù)的理解和使用,簡單舉例講解了inline關(guān)鍵字引出的內(nèi)聯(lián)函數(shù)的相關(guān)知識,需要的朋友可以參考下
    2016-01-01
  • 定義vim配置文件vimrc用于c/c++編程

    定義vim配置文件vimrc用于c/c++編程

    vim作為Linux下廣受贊譽的代碼編輯器,其獨特的純命令行操作模式可以很大程度上方便編程工作,通過自定義vim配置文件可以實現(xiàn)對vim功能的個性化設(shè)置。這篇文章主要介紹了定義vim配置文件vimrc,用于c/c++編程 ,需要的朋友可以參考下
    2018-10-10

最新評論