偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

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

一、基本限制

參數(shù)和返回類型必須是字面類型。

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

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

1. C++ 標(biāo)準(zhǔn)規(guī)定,以下類型屬于字面類型:

(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) 數(shù)組類型

數(shù)組的元素必須是字面類型。

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

(4) 字面值類(Literal Class)

類的所有非靜態(tài)成員必須是字面類型。

必須有一個(gè) constexpr 構(gòu)造函數(shù)(可以是默認(rèn)構(gòu)造函數(shù)或帶參數(shù)的構(gòu)造函數(shù))。

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

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

(5) void(C++14 起)

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

(6) 標(biāo)準(zhǔn)庫(kù)中的某些類型

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"; // 合法,數(shù)據(jù)是編譯期字面量
// constexpr std::string_view sv2 = std::string("runtime"); // 錯(cuò)誤:非編譯期數(shù)據(jù)

std::string("runtime") 會(huì)創(chuàng)建一個(gè)臨時(shí) std::string 對(duì)象,它的底層數(shù)據(jù)(存儲(chǔ)字符的數(shù)組)在內(nèi)存中的生命周期僅限于當(dāng)前表達(dá)式。當(dāng)這行代碼執(zhí)行完畢時(shí),臨時(shí)對(duì)象會(huì)被銷毀,其底層數(shù)據(jù)也隨之失效。

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

這里最關(guān)鍵的就是數(shù)據(jù)來源的編譯期確定性!

2. 非字面類型的例子

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

  • std::string(因?yàn)樗膭?dòng)態(tài)內(nèi)存分配不能在編譯期確定)。
  • 帶有虛函數(shù)的類(C++20 之前)。
  • 包含非字面類型成員的類。
struct NonLiteral {
    std::string s;  // std::string 不是字面類型
    NonLiteral() {}  // 沒有 constexpr 構(gòu)造函數(shù)
};
// constexpr NonLiteral nl;  // 錯(cuò)誤:NonLiteral 不是字面類型

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

constexpr 的核心目標(biāo)是編譯期計(jì)算,因此:

  • 編譯期可構(gòu)造:字面類型的對(duì)象可以在編譯期初始化。
  • 編譯期可求值:constexpr 函數(shù)的參數(shù)和返回值必須是編譯期可確定的。
  • 避免運(yùn)行時(shí)依賴:非字面類型(如 std::string)可能涉及動(dòng)態(tài)內(nèi)存分配,無法在編譯期處理。

二、禁止的操作

以下操作在 constexpr 函數(shù)中不允許出現(xiàn):

1. 動(dòng)態(tài)內(nèi)存分配

用new/delete 或堆內(nèi)存操作。

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

2. 異常處理

不能使用 throw 或 try-catch。

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

3. 調(diào)用非 constexpr 函數(shù)

只能調(diào)用其他 constexpr 函數(shù)或編譯器內(nèi)建函數(shù)

int non_constexpr(int x) { return x; }

constexpr int invalid_call(int x) {
    return non_constexpr(x); // 錯(cuò)誤:調(diào)用了非 constexpr 函數(shù)
}

4. 修改全局/靜態(tài)變量

編譯時(shí)上下文無法處理副作用。

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

靜態(tài)變量:

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

由于它們的初始化可能依賴運(yùn)行時(shí)狀態(tài),constexpr 無法保證編譯期確定性。

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

C++標(biāo)準(zhǔn)規(guī)定,constexpr函數(shù)中不能包含對(duì)具有靜態(tài)存儲(chǔ)期變量的賦值或修改操作。

三、成員函數(shù)的特殊規(guī)則

1. 虛函數(shù)

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

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

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

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

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

我理解是:

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

四、遞歸深度限制

即使遞歸邏輯合法,編譯器對(duì) constexpr 遞歸深度有默認(rèn)限制(如 GCC 默認(rèn) 512 層)。超出限制時(shí)需通過編譯選項(xiàng)調(diào)整:

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

五、版本差異總結(jié)

特性

C++11

C++14+

C++20

函數(shù)體復(fù)雜度

單條

允許循環(huán)、變量

進(jìn)一步擴(kuò)展

虛函數(shù)支持

不支持

不支持

支持

成員函數(shù)隱式

示例:合法與非法用法對(duì)比

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

// 非法:動(dòng)態(tài)內(nèi)存分配
constexprint* create(){
    int* p = newint(10);
    return p;
}

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


責(zé)任編輯:趙寧寧 來源: CppPlayer
相關(guān)推薦

2025-05-20 10:00:00

C++命名空間別名代碼

2025-05-20 08:10:00

函數(shù)函數(shù)類型函數(shù)指針類型

2021-10-27 11:00:30

C++語言面試

2024-02-21 23:13:45

C++編程開發(fā)

2010-01-27 17:16:52

C++構(gòu)造函數(shù)

2010-01-26 10:42:26

C++函數(shù)

2023-10-08 08:48:38

C++constexpr

2010-01-19 13:43:59

C++函數(shù)

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*函數(shù)開發(fā)

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++數(shù)組

2010-01-25 10:25:19

C++變量

2010-01-28 16:31:54

C++類型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)