现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34196 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

15 | constexpr:一个常态的世界

std::array<int, sqr(3)> a;
const int n = sqr(3); int a[n];
int main() { int a[sqr(3)]; }
int sqr(int n) { return n * n; }
参考资料
缺点和意义
内容小结
Main output function
Element output function for containers
Output function for std::pair
Type trait to detect whether an output function already exists
Type trait to detect std::pair
if constexpr 示例
constexpr 变量仍是 const
constexpr 变量模板
内联变量
constexpr 构造函数和字面类型
constexpr 函数限制
阶乘函数示例
编译期常量计算
constexpr 改造示例
constexpr 实际规则
constexpr 函数
constexpr 变量
示例代码
课后思考
output_container.h 解读
if constexpr
constexpr 和 const
constexpr 和编译期计算
初识 constexpr
constexpr: 一个常态的世界

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
我们已经连续讲了几讲比较累人的编译期编程了。今天我们还是继续这个话题,但是,相信今天学完之后,你会感觉比之前几讲要轻松很多。C++ 语言里的很多改进,让我们做编译期编程也变得越来越简单了。

初识 constexpr

我们先来看一些例子:
int sqr(int n)
{
return n * n;
}
int main()
{
int a[sqr(3)];
}
想一想,这个代码合法吗?
看过之后,再想想这个代码如何?
int sqr(int n)
{
return n * n;
}
int main()
{
const int n = sqr(3);
int a[n];
}
还有这个?
#include <array>
int sqr(int n)
{
return n * n;
}
int main()
{
std::array<int, sqr(3)> a;
}
此外,我们前面模板元编程里的那些类里的 static const int 什么的,你认为它们能用在上面的几种情况下吗?
如果以上问题你都知道正确的答案,那恭喜你,你对 C++ 的理解已经到了一个不错的层次了。但问题依然在那里:这些问题的答案不直观。并且,我们需要一个比模板元编程更方便的进行编译期计算的方法。
在 C++11 引入、在 C++14 得到大幅改进的 constexpr 关键字就是为了解决这些问题而诞生的。它的字面意思是 constant expression,常量表达式。存在两类 constexpr 对象:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

C++11引入了`constexpr`关键字,C++14对其进行了大幅改进,使得编译期编程变得更加简单。`constexpr`关键字用于定义编译时完全确定的常量和函数,允许进行编译期计算。通过`constexpr`函数,可以在编译期间产生编译期常数,从而实现编译期计算。与`const`的区别在于,`constexpr`表示编译期常数,而`const`表示运行时常量。C++17引入了内联变量的概念,允许在头文件中定义内联变量,解决了类的静态常量需要有一个定义的问题。此外,C++14引入了变量模板的概念,允许更简洁地表达类型相关的编译期常量。需要注意的是,`constexpr`变量仍然是const常类型。总之,`constexpr`关键字为C++编程带来了更多的编译期计算能力,使得编译期编程变得更加简单和灵活。文章还介绍了`if constexpr`的使用,以及`output_container.h`中的C++语法特性,展示了编译期常量表达式和编译期条件语句的应用,以及容器输出函数的实现。这些新特性对编译期编程有了很大的改进,可以让代码变得更直观。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(21)

  • 最新
  • 精选
  • 李亮亮
    我觉得我学习这个专栏只是为了能看懂这些新特性,写是写不出来,规则太多太复杂了。

    作者回复: 很少需要自己写的。就像学了微积分大部分人也没机会用一样😂。但一点都看不懂也是会很有问题的。

    2019-12-30
    11
  • czh
    老师好,有个小疑问,文中提到: “上一讲的结尾,我们给出了一个在类型参数 C 没有 reserve 成员函数时不能编译的代码:” 这里提到使用 if constexpr,可以解决上述问题。这里没有过多的解释,我理解是:使用if constexpr之后,如果没有reserve成员,那就会在编译期跳过这个if中的内容,因此不会检查container.reserve()。 不知道理解是否正确?

    作者回复: 对。一般的 if 是运行期条件语句;if constexpr 是编译期条件语句。

    2020-02-04
    2
    9
  • geek
    试着回答一下两个思考问题: 1 我认为不用consexpr,就要用enable_if,类似于上一节的append方法那样,在有两种可能情况时,要写两个方法,做标签分发。这种方式的一个推广就是:有多少种可能,就要写多少个对应的分发方法。 2 不用constexpr的缺点,就是代码冗余而且不易读。那么用constexpr的优点就是代码无冗余,易读。

    作者回复: 嗯。再补充一个,如果你有n个不同的静态条件,你需要分发的函数数量是 2^n。🤓

    2021-03-08
    2
    2
  • Jerry Tan
    您好老师, 请问想学C++ 您有什么比较好的推荐的开发工具吗 谢谢

    作者回复: 第 21 讲会讨论一点工具。不过你指的是什么工具呢?……如果你用 Windows,就从 Visual Studio 的免费 Community 版开始吧。

    2019-12-30
    5
    2
  • Slience-0°C
    常量区分编译期?和运行期?

    作者回复: 对,这是很重要的一个概念。能编译期确定的东西才能做编译期计算。

    2022-02-18
    1
  • Slience-0°C
    老师好,现代C++如何优雅的定义字符串常量?直接使用const std::string var = "xxxx "有些静态代码检查工具会提示可能会抛出无法捕获的异常!

    作者回复: 像你这种用法可以考虑用 std::string_view。 可参考我这个知乎回答: https://www.zhihu.com/question/483774144/answer/2251359893

    2022-02-18
    1
  • 心态正常
    吴老师,您好,有个问题想请教一下,文章开头的两个示例我在centos8上使用g++ 8.3.1的编译器编译通过了,因为没有用到constexpr的特性,预期在int a[n]这一行会报错,但是实际上并没有给出错误,这是编译器做了优化处理吗?

    作者回复: 是可以过的。只有第三个例子,模板参数,才会要求特别严。 不是考大家知道哪些行哪些不行。正如下面写的:“这些问题的答案不直观。”

    2021-04-26
    1
  • 清水
    吴老师,你好,请教个问题 constexpr int factorial(int n) { if (n == 0) { return 1; } else { return n * factorial(n - 1); } } 如果constexpr 修饰函数 这样是编译不过的,提示not a return-statement (至少c++11不行) 没有尝试过是否其他编译器 多行编译 通过 如果修改为一行表达式是没问题的,那么这是constexpr关键字 用法要求还是其他原因导致?

    作者回复: 编译器太老,升级到至少支持C++14的编译器,比如GCC 7。 GCC 6也许也可以,但我没有环境。毕竟,现在GCC已经发布10.2了。这门课程期望你用GCC 7以上的编译器。

    2021-01-14
    1
  • talor
    您好, constexpr int a = 42; constexpr const int& b = a; 这个例子编译不过,编译器是gcc 10.2.1

    作者回复: 我大概知道你的问题了。这两句是不能放在函数体里的。constexpr 引用只能绑定到全局变量上。

    2020-08-30
    1
  • g_boshu
    吴老师您好,我对以下代码有点儿疑惑: // Type trait to detect std::pair template <typename T> struct is_pair : std::false_type {}; template <typename T, typename U> struct is_pair<std::pair<T, U>> : std::true_type {}; template <typename T> inline constexpr bool is_pair_v = is_pair<T>::value; template <typename T, typename U> struct is_pair<std::pair<T, U>>: std::true_type {}; 看着应该是一个偏特化,模板的参数却变多了,一般偏特化不应该是参数变少吗?谢谢

    作者回复: 是偏特化。没有规定说偏特化一定参数更少啊。

    2020-04-01
    1
收起评论
显示
设置
留言
21
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部