导读:本期聚焦于广州网站建设创作的《c++中constexpr和const的区别是什么?编译期常量与运行期常量深度解析》,敬请观看详情。同样是修饰常量,constexpr和const在C++里却有着完全不同的含义:const只承诺运行期不可修改,而constexpr要求编译期就能算出结果。本文从初始化要求、数组尺寸、模板参数、switch的case标签等具体使用场景入手,分析两者的本质差异,并介绍C++11到C++17各版本对constexpr的扩展,包括constexpr函数、constexpr成员函数以及if constexpr等特性,帮助你彻底分清编译期常量与运行期常量,写出更高效的代码。

在C++代码里,constconstexpr都能用来修饰变量,很多人以为它们只是新旧写法的区别,实际上两者语义差别很大。const的含义是“运行期不可修改”,它修饰的变量完全可以在运行期才完成初始化;而constexpr的含义是“编译期常量”,它要求变量的值在编译阶段就必须确定下来。这个差别会直接影响到数组长度、模板实参、case标签等场景能否编译通过。

c++中constexpr和const的区别是什么?编译期常量与运行期常量深度解析

一、const的本质:只读承诺,而非编译期常量

const关键字最初的定位是“只读”,它向编译器承诺这个变量初始化之后不再被修改,但它并不要求初始化发生在编译期。看下面这段代码:

int get_value() {
    int x;
    std::cin >> x;
    return x;
}

const int a = 10;          // 编译期初始化,可以用作数组长度
const int b = get_value(); // 运行期初始化,只是一个只读变量

这里变量b虽然是const,但它的值要等用户输入之后才能确定,编译器在编译阶段根本不知道它是多少,所以它只是一个“运行期只读变量”。这样的const变量不能用作数组维度,不能传给模板的非类型参数,也不能用在case标签里。

而变量a在编译期就完成了初始化,某些编译器会把它放进符号表,甚至参与常量折叠优化。但要注意,这只是编译器的优化行为,从语言标准的角度,const本身并没有强制编译期求值的要求。换句话说,const修饰的变量“可能是”编译期常量,也可能不是,取决于初始化表达式能否在编译期求值。

二、constexpr的强约束:编译期必须算出结果

constexpr是C++11引入的关键字,它的语义比const严格得多:被它修饰的变量必须能由常量表达式初始化,否则直接编译报错。这个约束反而成了优点,它把“我想在编译期计算”的意图明确告诉编译器,编译器会帮你验证这一点。

constexpr int square(int n) {
    return n * n;
}

constexpr int len = square(5);        // 正确:编译期算出25
int arr[square(5)];                   // 正确:可作数组维度

const int c = rand();                 // 编译通过:运行期初始化
constexpr int d = rand();             // 编译错误:rand不是常量表达式

上面最后两行是区分两者最典型的例子:同一个初始化表达式,const能编译通过,constexpr直接报错。这不是constexpr的缺陷,而是它的设计目的,让你在写代码时就发现“这个值编译期算不出来”,而不是等到使用处才发现问题。

constexpr函数也有一些要求。在C++11中,constexpr函数体内只能有一条return语句;C++14放宽了限制,允许局部变量、循环、条件分支;C++17进一步允许constexpr Lambda和if constexpr。如果用constexpr修饰指针,需要注意它修饰的是指针本身而非所指对象,这点与const恰好相反。

三、典型使用场景对比

最直观的对比是数组定义。C++要求数组长度必须是编译期常量,两种写法的表现完全不同:

int n;
std::cin >> n;

const int size1 = n;     // 编译通过
// char buf[size1];      // 编译错误:size1不是常量表达式
constexpr int size2 = 100;
char buf[size2];         // 正确

在模板编程中,非类型模板参数同样要求编译期常量。假如有一个template<int N>这样的模板,传入const变量会导致编译失败,而constexpr变量可以正常实例化。switch语句的case标签也是同理,case后面必须跟常量表达式,只有编译期常量才能胜任。

另一个容易混淆的点是constexpr成员函数。在类中声明为constexpr的成员函数表示它可以在常量表达式中被调用,配合constexpr构造函数就能在编译期构造对象,比如常用的字面值类型。此外constexpr还支持递归调用,配合模板可以在编译期完成复杂计算,这是元编程的重要手段之一。

四、如何选择:按需求而非习惯

选择原则其实很简单:如果希望这个值一定在编译期确定,就用constexpr,比如数组长度、位掩码、数学常量、模板参数;如果只是想表达“这个值初始化后不允许修改”,比如函数内对外部数据的只读引用、运行期才能获得的配置值,用const更合适,因为强行加constexpr会导致编译失败。

从C++17开始,constexpr变量被隐式声明为const且内部链接,而C++11里constexpr成员函数并不隐含const,这个细节在C++14中已修正。实践中还有一条经验法则:能用constexpr就用constexpr,让编译器帮你把关;确实做不到编译期求值的场景,再退回const。理解了“只读承诺”与“编译期求值”这两个核心语义,两者之间的界限就再也不会混淆了。

constexprconstC++编译期常量修改时间:2026-09-03 01:26:59

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260903/49260.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。