跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

现代 C++ 新特性 constexpr 详解:从 C++11 到 C++20 的演进

综述由AI生成现代 C++ 中 constexpr 关键字从 C++11 到 C++20 经历了显著演进。内容涵盖常量表达式概念、constexpr 修饰函数及类的规则变化。重点解析了 C++14 放宽局部变量和循环限制、C++17 支持 Lambda 表达式以及 C++20 引入的动态内存分配和虚函数支持。这些特性使编译期计算能力大幅提升,有助于提升程序性能和实现更复杂的元编程逻辑。

极客零度发布于 2026/3/24更新于 2026/5/2118 浏览
现代 C++ 新特性 constexpr 详解:从 C++11 到 C++20 的演进

一、从 C++11 引入

1. 常量表达式和 constexpr 关键字的概念

现代 C++ 从 C++11 开始引入了常量表达式(constant expression)和 constexpr 关键字,并在后续标准中不断更新。

常量表达式是指值不会改变且在编译过程中就能得到计算结果的表达式。用字面量或常量表达式初始化的 const 对象属于常量表达式,但用变量初始化的 const 对象则不是。

#include <iostream>
using namespace std;

const int a = 1; // a 是常量表达式
const int b = a + 1; // b 是常量表达式
int c = 1; // c 不是常量表达式
const int d = c; // d 不是常量表达式,因为编译期无法确定 c 的值是否会被修改

由于常量表达式的值在编译期即可确定,编译器可以直接进行优化替换。通过汇编代码对比可以看出,使用常量表达式的地方直接替换了数值,从而提升了运行时的性能。

constexpr 变量示例

C++11 引入 constexpr 关键字用于指定常量表达式,允许在编译时计算表达式的值。constexpr 可以修饰变量,但被修饰的变量必须是常量表达式,且必须用常量或常量表达式初始化,否则会报错。

constexpr 也可以修饰指针,此时修饰的是指针本身(顶层 const)。

注意区分顶层 const 和底层 const:对象本身被 const 修饰为顶层 const,指向的对象被 const 修饰为底层 const。大多数普通对象被 const 修饰时是顶层 const;指针被 const 修饰时,* 左边的 const 是底层 const,* 右边的 const 是顶层 const;const 修饰引用时则是底层 const。

2. constexpr 修饰函数

constexpr 可以修饰函数,默认都是 inline 的,编译器会在编译时期执行计算。但由于函数逻辑比表达式复杂,C++11 对 constexpr 函数的要求非常严格:

  • 参数和返回值必须是字面类型(如整型、浮点型、指针、引用等)
  • 函数体只能包含一条语句,且必须是 return 语句
  • 不能定义局部变量,不能有循环或条件语句
  • 必须有返回值,且返回值为常量表达式

关键点: constexpr 函数的结果必须用常量表达式接收,才能触发编译优化。否则它仍像普通函数一样在运行时调用。

#include <iostream>
using namespace std;

constexpr int func1() { return 1; }
constexpr int func2(int x) { return x + 10; }
constexpr int func3(int n) { return n <= 1 ? 1 : n * func3(n - 1); }

int main() {
    constexpr int a = func1();
    constexpr int b = func2(10);
    constexpr int c = func3(5);
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
    return 0;
}

观察汇编语句可以发现,a、b、c 的结果在编译期就已经计算完成,cout 语句中直接进行了值替换。

constexpr 函数汇编示例

此外,constexpr 还能修饰其他函数:

  • 构造函数:类的所有成员变量必须是字面类型;构造函数必须在初始化列表中初始化所有成员变量,且必须用常量表达式初始化;函数体必须为空;析构函数不能做任何实际清理工作。
  • 成员函数:自动成为 const 成员函数,参数列表后需加 const,函数内不能修改成员变量;不能是虚函数;其他要求同普通函数。
  • 函数模板:如果实例化结果不符合 constexpr 普通函数的要求,constexpr 会自动忽略,该函数相当于普通函数。

可以看出,C++11 对 constexpr 的限制相当严格,但这些规定在后续标准中逐步放宽了。

二、constexpr 在 C++14 中的进化

C++14 大幅放宽了对 constexpr 函数的限制,使其语法和功能更接近普通函数:

  • 允许声明和初始化局部变量
  • 支持 if、for/while、switch 等控制流语句
  • 允许多条 return 语句
  • 返回类型可以是 void、自定义类型、STL 容器(如 std::array)等复合类型

实验时需确保编译器支持 C++14 标准。

#include <iostream>
using namespace std;

constexpr int func(int n) {
    if (n == 1 || n == 2) {
        return n;
    }
    int ret = 1; // 允许局部变量
    for (int i = 2; i <= n; i++) {
        ret *= i;
    }
    return ret; // 允许多条 return 语句
}

int main() {
    constexpr int a = func(5);
    cout << a << endl;
    return 0;
}

C++14 constexpr 示例

三、constexpr 在 C++17 中的进化

C++17 进一步扩展了 constexpr 的能力,模糊了编译时和运行时的界限。

其中,constexpr 可以修饰 lambda 表达式,要求捕获必须是常量表达式,且函数体满足 constexpr 函数的要求。

#include <iostream>
using namespace std;

int main() {
    constexpr int a = 10;
    constexpr auto func = [a](int x) constexpr {
        return x * a;
    };
    constexpr int b = func(5);
    cout << b << endl;
    return 0;
}

C++17 constexpr lambda

四、constexpr 在 C++20 中的进化

C++20 是对 constexpr 特性的重大更新,使其成为现代 C++ 元编程和性能优化的核心工具。主要更新包括:

  • 动态内存分配:支持在 constexpr 函数中使用 new/delete,但分配的内存必须在编译期释放。这使得 STL 容器在编译期的实现成为可能,但目前还无法在 constexpr 函数内真正使用 vector、string 等容器的内存操作。
  • 异常处理:支持 try-catch 语句,但不能真正抛出异常。主要用于模板约束和编译期错误检测,异常必须在编译期捕获和处理。
  • 可变成员变量:支持 constexpr 可变(mutable)类成员变量。原 constexpr 成员函数中不能修改成员变量,C++20 后加上 mutable 关键字即可在 constexpr 成员函数中修改。
  • 虚函数:支持将虚函数定义为 constexpr 函数,实现了编译期的多态调用。

C++23 是目前最新的标准,但编译器支持仍在路上。让我们期待 C++ 未来的发展吧!

目录

  1. 一、从 C++11 引入
  2. 1. 常量表达式和 constexpr 关键字的概念
  3. 2. constexpr 修饰函数
  4. 二、constexpr 在 C++14 中的进化
  5. 三、constexpr 在 C++17 中的进化
  6. 四、constexpr 在 C++20 中的进化
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 大模型新手指南:推荐五本核心入门书籍
  • Cursor IDE 中 Java 项目无法跳转到方法定义问题解决方案
  • 在 Cursor 中配置和使用 MCP 服务
  • HarmonyOS 应用开发:相对与栅格布局详解
  • 行星减速器:原理、计算公式与 C++ 实现
  • 数据结构:KMP 算法、Trie 树与并查集详解
  • Python 四大 Web 框架对比:FastAPI、Django、Flask 与 Tornado
  • 华为 ARM Linux 部署 Ollama 0.17.6 运行 Qwen3.5 模型测试
  • 数学与计算机:逻辑与算法的浪漫邂逅
  • Python 生成器函数深度解析:asyncio 事件循环底层实现与异步编程实战
  • C++ 无锁队列(Lock-Free Queue)详解
  • 黑客入门指南:零基础掌握核心安全能力与技能路径
  • DeepSeek 时代前端开发者能做什么
  • 鸿蒙金融理财全栈项目:生态合作与用户运营优化
  • 基于llama.cpp的Qwen3.5单GPU部署与股票筛选实战
  • MCP 插件配置与使用:browser-tools-mcp 示例
  • MCP 插件配置指南:以 browser-tools-mcp 为例
  • MCP 插件配置与使用:以 browser-tools-mcp 为例
  • 机器人路径规划:D* Lite算法应对动态障碍物及Python实现
  • 机器人动力学:牛顿欧拉法推导与详解

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online