成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++ 面試題:C++中 constexpr 函數的限制有哪些?

開發
在 C++ 中,字面類型(Literal Type) 是指可以在編譯期確定其值的類型,是支持編譯期計算的基礎。

注意這道面試題,問的不是 constexpr 的用法,是限制有哪些?

一、基本限制

參數和返回類型必須是字面類型。

我們理解下什么是字面類型?

在 C++ 中,字面類型(Literal Type) 是指可以在編譯期確定其值的類型,是支持編譯期計算的基礎。

1. C++ 標準規定,以下類型屬于字面類型:

(1) 基本類型

int, char, bool, float, double, long, short, unsigned 等。

nullptr_t(C++11 起)。

constexpr int x = 42;  // int 是字面類型
constexpr char c = 'A'; // char 是字面類型

(2) 引用類型

引用必須綁定到字面類型。

constexpr int a = 10;
constexpr const int& ref = a;  // 引用是字面類型

(3) 數組類型

數組的元素必須是字面類型。

constexpr int arr[] = {1, 2, 3};  // int[] 是字面類型

(4) 字面值類(Literal Class)

類的所有非靜態成員必須是字面類型。

必須有一個 constexpr 構造函數(可以是默認構造函數或帶參數的構造函數)。

不能有虛函數。(C++20允許字面類型包含虛函數,但是需要滿足不少條件)

struct Point {  // 字面值類
    int x, y;
    constexpr Point(int x = 0, int y = 0) : x(x), y(y) {}  // constexpr 構造函數
};
constexpr Point p(1, 2);  // 編譯期構造

(5) void(C++14 起)

void 也可以算作字面類型,但通常不能直接用于 constexpr 變量。

(6) 標準庫中的某些類型

std::array(如果 T 是字面類型)。

std::string_view(C++17 起)。

#include <array>
constexpr std::array<int, 3> arr = {1, 2, 3};  // std::array 是字面類型

constexpr std::string_view sv = "compile-time"; // 合法,數據是編譯期字面量
// constexpr std::string_view sv2 = std::string("runtime"); // 錯誤:非編譯期數據

std::string("runtime") 會創建一個臨時 std::string 對象,它的底層數據(存儲字符的數組)在內存中的生命周期僅限于當前表達式。當這行代碼執行完畢時,臨時對象會被銷毀,其底層數據也隨之失效。

std::string("runtime") 生成的臨時對象在編譯期上下文中仍然會“邏輯銷毀”,導致 string_view 引用的底層數據在編譯期就失效。

這里最關鍵的就是數據來源的編譯期確定性!

2. 非字面類型的例子

以下類型不是字面類型,因此不能用于 constexpr 上下文:

  • std::string(因為它的動態內存分配不能在編譯期確定)。
  • 帶有虛函數的類(C++20 之前)。
  • 包含非字面類型成員的類。
struct NonLiteral {
    std::string s;  // std::string 不是字面類型
    NonLiteral() {}  // 沒有 constexpr 構造函數
};
// constexpr NonLiteral nl;  // 錯誤:NonLiteral 不是字面類型

3. 為什么 constexpr 限制要求字面類型?

constexpr 的核心目標是編譯期計算,因此:

  • 編譯期可構造:字面類型的對象可以在編譯期初始化。
  • 編譯期可求值:constexpr 函數的參數和返回值必須是編譯期可確定的。
  • 避免運行時依賴:非字面類型(如 std::string)可能涉及動態內存分配,無法在編譯期處理。

二、禁止的操作

以下操作在 constexpr 函數中不允許出現:

1. 動態內存分配

用new/delete 或堆內存操作。

constexpr int* invalid() {
    int* p = new int(42); // 錯誤:不能在編譯時分配內存
    return p;
}

2. 異常處理

不能使用 throw 或 try-catch。

constexpr int unsafe(int a) {
    if (a < 0) throw "negative"; // 錯誤:不允許異常
    return a;
}

3. 調用非 constexpr 函數

只能調用其他 constexpr 函數或編譯器內建函數

int non_constexpr(int x) { return x; }

constexpr int invalid_call(int x) {
    return non_constexpr(x); // 錯誤:調用了非 constexpr 函數
}

4. 修改全局/靜態變量

編譯時上下文無法處理副作用。

全局變量:在程序啟動時(main() 之前)初始化。

靜態變量:

  • 局部 static 變量在第一次進入作用域時初始化(運行時)。
  • 全局 static 變量類似于全局變量。

由于它們的初始化可能依賴運行時狀態,constexpr 無法保證編譯期確定性。

int global = 0;
constexpr void modify_global() {
    global++; // 錯誤:修改全局變量
}

C++標準規定,constexpr函數中不能包含對具有靜態存儲期變量的賦值或修改操作。

三、成員函數的特殊規則

1. 虛函數

  • C++20 前:虛函數不能是 constexpr。
  • C++20 起:允許虛函數為 constexpr。
struct Base {
    virtual constexpr int foo() { return 1; } // C++20 合法
};

2. 隱式 const 限定(C++11)

  • C++11:constexpr 成員函數隱式為 const。
  • C++14:取消此限制,允許修改對象狀態。
struct Widget {
    int value = 0;
    constexpr void update() { value++; } // C++14+ 合法
};

這里其實開始不是很理解,成員變量的修改其實是運行時行為,但是現在要在編譯期搞,查了下資料是這么說的:

constexpr成員函數修改成員變量,在編譯期是邏輯行為,運行時才是真實修改
。是邏輯上的(編譯器模擬,不生成實際的內存寫入)。

我理解是:

  • 對 value 的修改發生在編譯期,最終生成的 value 是一個編譯期常量對象,其狀態被“凍結”為 count = 1。
  • 沒有運行時開銷,value 的值直接編譯進二進制。
  • 這里的“修改”只是邏輯上的操作,不涉及真實內存寫入。
  • 運行時調用 update() 是真正的運行時行為,修改的是內存中的對象。
  • 代碼邏輯與編譯期版本相同,但發生在程序運行時。
  • 對比上面說的全局變量,類成員變量的對象是局部的影響可控,全局變量可能被其他地方修改,所以類成員變量這里可以放開,但是全局變量不行。

四、遞歸深度限制

即使遞歸邏輯合法,編譯器對 constexpr 遞歸深度有默認限制(如 GCC 默認 512 層)。超出限制時需通過編譯選項調整:

g++ -fconstexpr-depth=1000 main.cpp

五、版本差異總結

特性

C++11

C++14+

C++20

函數體復雜度

單條

允許循環、變量

進一步擴展

虛函數支持

不支持

不支持

支持

成員函數隱式

示例:合法與非法用法對比

// 合法:C++14+ 允許循環和局部變量
constexprintsum(int n){
    int total = 0;
    for (int i = 0; i < n; ++i) {
        total += i;
    }
    return total;
}

// 非法:動態內存分配
constexprint* create(){
    int* p = newint(10);
    return p;
}

// 合法:C++20 虛函數
structBase {
    virtualconstexprintget(){ return1; }
};


責任編輯:趙寧寧 來源: CppPlayer
相關推薦

2025-05-20 10:00:00

C++命名空間別名代碼

2025-05-20 08:10:00

函數函數類型函數指針類型

2021-10-27 11:00:30

C++語言面試

2024-02-21 23:13:45

C++編程開發

2010-01-27 17:16:52

C++構造函數

2010-01-26 10:42:26

C++函數

2023-10-08 08:48:38

C++constexpr

2010-01-19 13:43:59

C++函數

2025-05-26 03:20:00

2010-01-21 09:34:57

C++語法

2010-01-27 16:05:06

C++堆棧

2011-03-29 14:31:41

CC++

2025-04-30 10:10:00

在 C++C++11Lambda

2025-05-27 10:15:00

void*函數開發

2010-01-21 14:07:14

CC++聲明

2025-05-09 09:25:00

2025-05-06 08:20:00

互斥鎖C++編程

2010-01-20 10:19:55

C++數組

2010-01-25 10:25:19

C++變量

2010-01-28 16:31:54

C++類型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本不卡一区二区三区 | 精品久久久久久久久久 | 亚洲在线视频 | 91原创视频在线观看 | 国产精品揄拍一区二区久久国内亚洲精 | 亚洲精品视频在线看 | 一区二区三区在线电影 | 99久久婷婷国产综合精品电影 | 韩国电影久久 | 欧美a v在线 | 欧美一级欧美三级在线观看 | 亚洲视频免费观看 | 91av在线免费 | 成人一级毛片 | 黄色大片毛片 | 亚洲国产精品一区二区久久 | 精品九九 | 欧美日韩一 | 精精国产xxxx视频在线野外 | 亚洲欧美精品国产一级在线 | 免费一看一级毛片 | 国产在线观看av | 亚洲精品一区二区三区丝袜 | 久久一 | 国产精品视频网 | 久久三区| 亚洲成av片人久久久 | 国产成人精品午夜 | 国产精品一区视频 | 99成人免费视频 | 81精品国产乱码久久久久久 | 中国黄色毛片视频 | av中文在线 | 欧美精品一区三区 | 久久精品亚洲精品国产欧美kt∨ | 欧美一区二区三区的 | 日韩图区| 日本亚洲欧美 | 国产精品99久久久精品免费观看 | 久婷婷 | cao视频|