Modern C++ ——constexpr的用法

Reference

《现代C++语言核心特性解析》

为什么引入constexpr

  1. const可以定义常量,但也可以用来定义只读变量。const变量的值不一定是在编译期可以确定的,比如当通过函数返回值进行初始化时。

  2. C++标准委员会决定在C++11标准中定义一个新的关键字constexpr,它能够有效地定义常量表达式,并且达到类型安全、可移植、方便库和嵌入式系统开发的目的。

constexpr值

  1. constexpr值即常量表达式值,该值必须编译期能够确定。

  2. 常量表达式值必须被常量表达式初始化。

constexpr函数 (C++11)

(1)什么是constexpr函数?

constexpr不仅能用来定义常量表达式值,还能定义一个常量表达式函数,即constexpr函数,常量表达式函数的返回值可以在编译阶段就计算出来。

(2)C++11约束规则

1.函数必须返回一个值,所以它的返回值类型不能是void。

2.函数体必须只有一条语句:return expr,其中expr必须也是一个常量表达式。如果函数有形参,则将形参替换到expr中后,expr仍然必须是一个常量表达式。

3.函数使用之前必须有定义。

4.函数必须用constexpr声明。

(3)特殊情况

  1. 用递归完成循环,实现函数体只有单语句。
//编译失败
constexpr int sum(int x)
{
int result = 0;
while (x > 0)
{
result += x--;
}
return result;
} //可改为
constexpr int sum(int x)
{
return x > 0 ? x + sum(x - 1) : 0;
}
  1. if else双分支可以用条件表达式替代
//编译失败
constexpr int abs2(int x)
{
if (x > 0) {
return x;
} else {
return -x;
}
}
//可改为
constexpr int sum(int x)
{
return x > 0 ? x + sum(x - 1) : 0;
}
  1. 当带形参的常量表达式函数接受了一个非常量实参时,常量表达式函数可能会退化为普通函数。

constexpr构造函数

(1)用途

constexpr可以声明基础类型从而获得常量表达式值,除此之外constexpr还能够声明用户自定义类型。

(2)相关规则:

1.构造函数必须用constexpr声明。

2.构造函数初始化列表中必须是常量表达式。

3.构造函数的函数体必须为空(这一点基于构造函数没有返回值,所以不存在return expr)。

(3)注意

最后需要强调的是,使用constexpr声明自定义类型的变量,必须确保这个自定义类型的析构函数是平凡的(Trivial destructor),否则也是无法通过编译的。平凡析构函数必须满足下面3个条件。

1.自定义类型中不能有用户自定义的析构函数。2.析构函数不能是虚函数。3.基类和成员的析构函数必须都是平凡的。

支持浮点数

在constexpr说明符被引入之前,C++程序员经常使用enum hack来促使编译器在编译阶段计算常量表达式的值。但是因为enum只能操作整型,所以一直无法完成对于浮点类型的编译期计算。constexpr说明符则不同,它支持声明浮点类型的常量表达式值,而且标准还规定其精度必须至少和运行时的精度相同

C++14对常量表达式函数的增强

1.函数体允许声明变量,除了没有初始化、static和thread_local变量。

2.函数允许出现if和switch语句,不能使用go语句。

3.函数允许所有的循环语句,包括for、while、do-while。

4.函数可以修改生命周期和常量表达式相同的对象。

5.函数的返回值可以声明为void。

6.constexpr声明的成员函数不再具有const属性。

#include <iostream>

class X {
public:
constexpr X() : x1(5) {}
constexpr X(int i) : x1(0)
{
if (i > 0) {
x1 = 5;
}
else {
x1 = 8;
}
}
constexpr void set(int i) // 函数的返回值可以声明为constexpr void。 可以在常量表达式函数中被调用
{
x1 = i;
}
constexpr int get() const
{
return x1;
}
private:
int x1;
}; constexpr X make_x()
{
X x;
x.set(42);
return x;
} int main()
{
constexpr X x1(-1);
constexpr X x2 = make_x();
constexpr int a1 = x1.get();
constexpr int a2 = x2.get();
std::cout << a1 << std::endl;
std::cout << a2 << std::endl;
}

C++17 constexpr lambda表达式

待续。

Modern C++ ——constexpr的各种用法的更多相关文章

  1. c++语言的学习笔记代码与笔记注释《函数部分》

    具体的笔记以注释的形式写在代码内,每个知识点用函数的形式表现. #include <iostream>; #include<cmath> const double PI=3.1 ...

  2. c++ constexpr用法

    测试环境:windows10 + gcc8.1 1.constexpr产生背景 c++11以后,为了保证写出的代码比以往任何时候的执行效率都要好而进行了许多改善.其中,这种改善之一就是生成常量表达式, ...

  3. Effective Modern C++ ——条款6 当auto型别不符合要求时,使用带显式型别的初始化物习惯用法

    类的代理对象 其实这部分内容主要是说明了在STL或者某些其他代码的容器中,在一些代理类的作用下使得最后的返回值并不是想要的结果. 而他的返回值则是类中的一个容器,看下面的一段代码: std::vect ...

  4. Effective Modern C++:01类型推导

    C++的官方钦定版本,都是以ISO标准被接受的年份命名,分别是C++98,C++03,C++11,C++14,C++17,C++20等.C++11及其后续版本统称为Modern C++. C++11之 ...

  5. [C++11] Effective Modern C++ 读书笔记

    本文记录了我读Effective Modern C++时自己的一些理解和心得. item1:模板类型推导 1)reference属性不能通过传值参数传入模板函数.这就意味着如果模板函数需要一个refe ...

  6. mysql CASE WHEN的基础和多种用法

    CASE计算条件列表并返回多个可能结果表达式之一. CASE 具有两种格式: 简单 CASE 函数将某个表达式与一组简单表达式进行比较以确定结果. CASE 搜索函数计算一组布尔表达式以确定结果. 两 ...

  7. 英文破折号(em dash)、连接号(en dash)与连字符(hyphen)的区别及各自用法是什么?

    英文破折号(em dash).连接号(en dash)与连字符(hyphen)的区别及各自用法是什么?在科技写作中有何特点?   2 条评论 分享   按票数排序按时间排序 6 个回答 赞同85反对, ...

  8. CppCon - Modern Template Metaprogramming 杂记

    2014年底才看到github和channel9上有CppCon2014的视频和资料,顿时激动不已.最近小生也一直在研习CppCon2014中令人兴奋的内容.这篇鄙文就是小生学习了<Modern ...

  9. css基础之 font的简写规则 以及 自定义 CSS3 @font-face详细用法

    Part 1 font简写 CSS的命名规则是用英文字母 数字 和下划线(一般用小写)来命名.简写css font的好处有三:一是写起来方便(就像键盘快捷键):二是简化代码:三是帮助你熟悉和深刻理解c ...

  10. @font-face的用法

    几乎所有浏览器(包括最古老的IE6)也支持的网络字体@font-face的用法是: @font-face { font-family: 'MyWebFont'; src: url('webfont.e ...

随机推荐

  1. Linux下文件实时自动同步备份

    转载简书: https://www.jianshu.com/p/fc2f3ec661c0

  2. 在vue-element-admin模板中去掉tui-editor

    先删除package.json的"tui-editor": "1.3.3",再安装依赖,不然会报错 1.修改package.json 删除包括tui-edito ...

  3. Vite 项目添加 Sass/Scss 并配置全局样式

    (1)在 Vite 项目里,只需要安装 sass: npm i -D sass (2)Sass 的全局变量,需要在vite.config.ts配置一项: css: { preprocessorOpti ...

  4. KingbaseES R6集群物理copy方式手工添加新备库节点

    案例说明:对于主库数据量比较大的环境,在添加新节点是可以采用在线clone方式创建新的备库节点,也可以在离线的状态下,直接拷贝其中一个备库的所有集群相关目录来创建新的备库节点.本案例介绍了通过离线物理 ...

  5. “堆内存持续占用高 且 ygc回收效果不佳” 排查处理实践

    作者:京东零售 王江波 说明:部分素材来源于网络,数据分析全为真实数据. 一. 问题背景 自建的两套工具,运行一段时间后均出现 内存占用高触发报警,频繁young gc且效果不佳.曾经尝试多次解决,因 ...

  6. linux系统下,添加硬盘并挂载到操作系统的shell 脚本范例

    #!/bin/sh #新添加硬盘挂载到操作系统 pvcreate /dev/sdb   / / 一般新添加硬盘都是识别为sdb,当然,也不一定,要具体情况具体分析. vgcreate datavg / ...

  7. 四大组件之广播接收者BroadcastReceiver

    参考:Android开发基础之广播接收者BroadcastReceiver 什么是广播接收者? 我们小时候都知道,听广播,收听广播!什么是收听广播呢?打开收音机,调频就可以收到对应的广播节目了.其实我 ...

  8. SpringMVC学习笔记【狂神说】

    1.MVC是什么 MVC是模型(Model).视图(View).控制器(Controller)的简写,是一种软件设计规范. 是将业务逻辑.数据.显示分离的方法来组织代码. MVC主要作用是降低了视图与 ...

  9. Mysql 原生语句

    1.SQL语句 1.1什么是SQL语句: SQL:结构化查询语言.关系数据库语言的国际标准. 各个数据库厂商都支持ISO的SQL标准:如普通话 各个数据库厂商在标准基础做了自己的扩展:如方言 1.2 ...

  10. 实验四:开源控制器实践——OpenDaylight

    实验要求: (一)基本要求: 1.利用Mininet平台搭建下图所示网络拓扑,并连接OpenDaylight控制器: 2.通过Postman工具调用OpenDaylight提供的API下发流表,实现拓 ...