constexpr 用于声明编译时常量或编译时计算的函数。

用它修饰的变量或者函数,可以在编译阶段计算出结果,而不是在运行时,既保证了常量的正确性,又提升了程序效率。

简单地说,就是,constexpr是 C++11 给 “编译期” 加的 “计算权限”—— 让变量 或者 函数能在编译时 “干活”,而不是等程序run起来才开始。

一、修饰变量:强制 “编译期常量”

替代了传统的const模糊常量性(即const可能是运行时常量,比如const int a = rand() ),constexpr变量必须在编译期间确定值,否则在编译时会报错。

示例:

constexpr int MaxNum = 100; // 编译期确定,可用于数组大小、模板参数等
int arr[MaxNum]; // 合法,因为MaxNum是编译期常量

const int b = 20; // 是常量,但本质是“运行时初始化后不可改”
constexpr int c = b; // 合法(b值编译期可知)
// 但如果 b=rand(),则c编译报错

二、修饰函数:“可编译期执行” 的函数

满足条件的constexpr函数,既可以像普通函数在运行时调用,也能在编译期被 “计算出结果”(比如给constexpr变量赋值时)。

限制条件(C++11标准):

① 函数体仅只有一条return语句(没有循环、分支等复炸逻辑)

② 参数和返回值必须是字面类型(如int、double、指针等,无自定义类对象)

示例:

// 编译期/运行:计算平方
constexpr int square(int x) {
    return x * x;
}
// 编译期计算,结果25
constexpr int a = square(5); 
// 运行时调用,和普通函数一样
int b = square(rand()); 

三、与const的区别

C++11中constexpr和const的核心区别是常量的确定时机 :const是 运行时不可更改,constexpr是编译期间必须确定。前者是只读,后者是编译期常量。

这个差异也导致了constexpr通常比const高效,因为constexpr强制编译期计算,直接规避了运行时的开销,而const仅保证了 “只读”,值可能仍需运行时确定

1、修饰变量:核心差异在值的确定时机

const变量:仅保证修饰变量的值 “初始化后不可修改”,但值的确定时机可以是运行时(只要初始化后不变)

例:const int a = rand(); rand()在运行时生成值,a 初始化后只读),但 a 不是 “编译期常量”,不能用于数组大小、模板参数。

constexpr变量:强制 “值在编译期确定”,否则编译报错。

例:constexpr int c = rand(); 编译报错(因为rand () 运行时才知道结果,无法满足编译期确定要求)。并且constexpr变量天然具备 “只读” 属性,可以说是比const更严格的 “常量”。

2. 修饰函数:constexpr有 “编译期执行” 能力,而const没有

const函数(非成员函数中,const仅能修饰成员函数,表示 “不修改对象状态”):无没有“编译期计算” 能力,只能在运行时调用。例如:const int add(int x, int y) { return x+y; }

注:非成员函数加const在 C++ 中不合法,仅类的成员函数可以使用const修饰 “不修改对象”)。

constexpr函数:满足限制条件时,既能在编译期计算结果(给constexpr变量赋值时),也能在运行时调用(像普通函数)。例:constexpr int square(int x) { return x*x; }

一句话总结它们的区别:

const是 “运行时只读的变量 / 不修改对象的函数”,constexpr是 “编译期必须确定的变量 / 能编译期执行的函数”。

四、constexpr的使用场景

constexpr的核心优势是编译期计算,适合用于 “值 或者 逻辑 可在编译阶段确定” 的场景,具体可分为 3 类:

1、定义编译期常量

需在编译时确定值、且后续不可改的场景,如:

①数组大小(C++ 中数组大小需编译期常量)

②模板参数(模板实例化依赖编译期确定的参数)

③枚举值、数学常量(如圆周率)

示例:

constexpr int MAX_SIZE = 10; 
int arr[MAX_SIZE]; // 合法,编译期确定数组大小

template<int N>
void printSize() { std::cout << N; }
printSize<MAX_SIZE>(); // 模板参数需编译期常量,constexpr适用

2、实现“编译期可计算”的简单逻辑

函数逻辑简单(如纯计算、无复杂分支 / 循环),且需要在编译期得到结果的场景,如:

①简单数学运算(平方、阶乘、数值转换)

示例:

// 编译期计算阶乘
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n-1);
}

constexpr int res = factorial(5); // 编译期算得120,运行时无开销

3、优化“运行时没有必要的计算”的场景

即使逻辑可在运行时执行,但用constexpr将计算提前到编译期,能减少运行时开销,如:

①固定配置的计算(如根据固定参数生成配置值)

②循环等待中的常量条件(编译期确定循环终止条件的基础值)

示例:

// 编译期计算确定固定配置的阈值,运行时直接使用
constexpr int MAX_SIZE = 1024 * 2; 

while (value < MAX_SIZE) {
    // 运行时不需要计算MAX_SIZE,直接用编译期得到的结果
}

五、小结

①效率提升:编译期计算避免运行时开销(比如常量计算、简单逻辑提前计算好);

②语法严谨:强制区分了“编译期常量” 和 “运行时常量”,减少因const模糊性导致的错误;

③支持元编程:为编译期逻辑(如模板参数、数组大小)提供合法的 “计算工具”。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐