C++11之constexpr

news2024/9/20 14:30:01

        注:大前提,本篇文章是在介绍C++11中的constexpr,自C++14以来constexpr有了非常大的改动,如在实验中遇见与本文不符的地方还先请查阅其他资料,确定为本文错误后可留言,我会虚心接受并改正。 

constexpr定义编译时常量

        在C++11中添加了一个新的关键字constexpr,这个关键字是用来修饰常量表达式的。所谓常量表达式,指的就是由多个(≥1)常量(值不会改变)组成并且在编译过程中就得到计算结果的表达式。常量表达式和非常量表达式的计算时机不同,非常量表达式只能在程序运行阶段计算出结果,但是常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。在C++11中添加了constexpr关键字之后就可以在程序中使用它来修饰常量表达式,用来提高程序的执行效率。在使用中建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr

        在定义常量时const和constexpr是等价的,都可以在程序的编译阶段计算出结果,并可以用来定义数组。

const int size_c = 1024;
constexpr int size_cpr = 2048;

int main()
{
	int array1[size_c] = { 1,2,3 };
	int array2[size_cpr] = { 3,4,5 };
	return 0;
}

        如果要定义一个结构体/类常量对象,可以这样写:

#include <iostream>
using namespace std;

template<class T>
struct Test1
{
	T t;
	int i;
	array<double, 3> arr; // array在栈上存数据
};

struct Test2
{
	string str;
	vector<int> v;
};

int main()
{
	constexpr Test1<char> t1{ 'a', 10, {1,2,3} }; // 必须要在定义时就赋值
	cout << t1.t << " " << t1.i << endl;
	int arr[t1.i] = {}; // 证实t1.i具有常量属性
	//t1.arr[0] = 10; //error constexpr修饰的对象的成员也是常量,不能进行修改
	//const/constexpr array<double, 3> a{ 5, 6, 7 };
	//t1.arr = a;

	//error 因为constexpr修饰的常量是在编译时确定的,而string、vector等容器的数据是存在堆上的,而程序对堆空间的管理是在运行时才开始的,所以会出现编译错误
	//constexpr Test2 t2{ "123", {1,2,3} }; 

	const Test2 t2{ "123", {1,2,3} }; // 这里的const不是声明t2为编译时常量(真常量),而是声明为运行时常量(只读属性)
	//t2.str = "000"; //error 只读对象的成员也是只读的
	return 0;
}

常量表达式函数

        为了提高C++程序的执行效率,我们可以将程序中值不需要发生变化的变量定义为常量,也可以使用constexpr修饰函数的返回值,这种函数被称作常量表达式函数,这些函数主要包括以下几种:普通函数/类成员函数、类的构造函数、模板函数。

        注:由于现在编译器版本都比较高,默认的使用的C++标准也比较高(大于C++11),相关源代码请基于 C++11 标准进行测试。

普通函数/类的成员函数

        constexpr并不能修饰任意函数的返回值,使这些函数成为常量表达式函数,必须要满足以下几个条件:

        函数必须要有返回值,return返回的表达式必须是常量表达式,并且整个函数的函数体内有且只能有一条return语句,不能出现除此之外的语句。(using、typedef、static_assert语句除外)(C++14对该规则有较大修改)

#include <iostream>
using namespace std;

// error 没有返回值
constexpr void test1()
{}

constexpr bool test2()
{
        using my_type = int;
        typedef int new_type;
        static_assert(10 > 0, "10 not greater than 0");
        return true;
}

constexpr int test3(int i)
{
	return i > 0 ? i : 0;
}

int main()
{
        test1();
        test2();
        
        int i;
        cin >> i;
        cout << test3(i) << endl;

        return 0;
}

        函数在使用之前,必须有对应的定义语句。 

#include <iostream>
using namespace std;

constexpr int test();
int main()
{
        // error 在定义前使用constexpr函数
        constexpr int res = test();
        cout << res << endl;
        return 0;
}

constexpr int test()
{
        return 1;
}

        注:以上规则不仅对应普通函数适用,对应类的成员函数也是适用的。


构造函数 

         如果想用直接得到一个常量对象,也可以使用constexpr修饰一个构造函数,这样就可以得到一个常量构造函数了。常量构造函数有一个要求:构造函数的函数体必须为空,并且必须采用初始化列表的方式为各个成员赋值。

        当我们在类的构造函数前加上constexpr关键字时,‌我们是在向编译器表明,‌只要传递给构造函数的参数都是constexpr,‌那么该构造函数就可以在编译时期执行,‌产生的对象也将是constexpr对象。‌这意味着,‌这样的对象可以在编译时期被初始化,‌并且可以在只允许使用constexpr的场合中使用。‌例如,‌constexpr对象可以用作常量,‌它们可以在编译时被计算和赋值给常量变量或枚举值。‌

#include <iostream>
using namespace std;

struct Test
{
public:
	constexpr Test() : i(0), d(0.0), c('0')
	{}
	~Test() = default;

	int i;
	double d;
	char c;
};

int main()
{
	// 错误用法,这样使用构建出的对象不是常量
	Test t1;
	cout << t1.i << " " << t1.d << " " << t1.c << endl;
	t1.i = 100;
	cout << t1.i << " " << t1.d << " " << t1.c << endl;
	Test t2;
	t1 = t2;
	cout << t1.i << " " << t1.d << " " << t1.c << endl;

	// 正确用法
	constexpr Test t3;
	//t3.i = 100; // error

	return 0;
}


模板函数

        C++11 语法中,constexpr可以修饰函数模板,但由于模板中类型的不确定性,因此函数模板实例化后的模板函数是否符合常量表达式函数的要求也是不确定的。如果constexpr修饰的模板函数实例化结果不满足常量表达式函数的要求,则constexpr会被自动忽略,即该函数就等同于一个普通函数

#include <iostream>
using namespace std;

struct Person
{
	const char* name_;
	uint16_t age_;
};

template<class T>
constexpr T dispatch(const T& t)
{
	return t;
}

int main()
{
	// 因为12345是字面量即常量,所以此时dispatch是常量表达式函数
	constexpr int ret = dispatch(12345);

	Person p1{ "zhangsan", 15 };
	// 因为p1是变量,不是常量表达式,所以dispacth函数的constexpr失效
	Person p2 = dispatch(p1);
	cout << p2.name_ << " " << p2.age_ << endl;


	constexpr Person p3{ "zhangsan", 15 };
	// 因为p3为常量,所以此时dispacth函数的constexpr有效
	constexpr Person p4 = dispatch(p3);
	cout << p4.name_ << " " << p4.age_ << endl;

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1929348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

惠海H5112A降压恒流芯片IC 60V72V80V100V转24V36V48V多路共阳输出景观LED点光源

H5112A是一款外围电路简单的多功能平均电流型LED恒流驱动器&#xff0c;适用于5-90V电压范围的非隔离式大功率恒流LED驱动领域。芯片采用了平均电流模式控制&#xff0c;输出电流精度在士3%;输出电流对输入输出电压以及电感不敏感;芯片内部集成了环路补偿&#xff0c;外围电路更…

学习测试9-接口测试 2-抓包工具Fiddler

Fiddler 抓包工具的使用 怎么找接口信息&#xff0c;可以通过浏览器的开发者工具 Fiddler 是一个 HTTP 协议调试代理工具 File 菜单&#xff1a; Capture Traffic&#xff08;或 F12&#xff09;&#xff1a;是个开关&#xff0c;可以控制是否把 Fiddler 注册为系统代理。当把…

Mac系统能装虚拟机吗 Mac装双系统虚拟机详细教程 macos可以用虚拟机装windows吗

随着科技的进步和用户需求的多样化&#xff0c;越来越多的用户希望在一台设备上运行多个操作系统。特别是对于Mac用户来说&#xff0c;安装虚拟机或者双系统已成为常见需求。这不仅可以满足用户在不同操作系统工作的需求&#xff0c;也可以让开发人员在不同的操作系统上进行测试…

【题目/训练】二叉树的创建遍历(递归非递归)

一、根据二叉树创建字符串 思路&#xff1a;在正常前序递归遍历的基础上&#xff0c;单独加上一个考虑到右子树为空的情况&#xff0c;如下&#xff1a;其结果为 1&#xff08;2&#xff08;4&#xff08;5&#xff09;&#xff08;6&#xff09;&#xff09;&#xff09;&…

财伯乐伯乐遇马税务师事务所品牌发布会圆满落幕!

7月14日 &#xff0c;由财伯乐主办&#xff0c;伯乐遇马集团、HRS卓玥学社联合主办的财伯乐&伯乐遇马税务师事务所品牌发布会在上海闵行区隆重召开。这场盛会不仅标志着财伯乐品牌的正式亮相&#xff0c;更预示着企业服务领域的一次创新和突破。来自行业的领袖、合作伙伴共…

React+TS前台项目实战(二十九)-- 首页构建之性能优化实现首页Echarts模块数据渲染

文章目录 前言Echart模块源码功能分析数据渲染一、HashRateEchart统计图1. 功能分析2. 代码详细注释 二、BlockTimeChart统计图1. 功能分析2. 代码详细注释 三、使用方式四. 数据渲染后效果如下 总结 前言 还记得之前我们创建的 高性能可配置Echarts组件 吗&#xff1f;今天我…

【刷题汇总 -- 乒乓球筐、组队竞赛、删除相邻数字的最大分数】

C日常刷题积累 今日刷题汇总 - day0141、乒乓球筐1.1、题目1.2、思路1.3、程序实现 2、组队竞赛2.1、题目2.2、思路2.3、程序实现 3、删除相邻数字的最大分数3.1、题目3.2、思路3.3、程序实现 -- dphash 4、题目链接 今日刷题汇总 - day014 1、乒乓球筐 1.1、题目 1.2、思路 …

RflySim工具链常见问题解答

7月10日&#xff0c;卓翼飞思实验室暑期公益培训首场直播圆满落幕&#xff0c;共吸引2400余名学员参与。本期直播培训以“RflySim-智能无人集群系统快速开发与验证工具链”为主题&#xff0c;对RflySim工具链的功能和资源框架进行了全面详细的介绍。本文将针对使用RflySim工具链…

数据结构-java中链表的存储原理及使用方式

目录 链表&#xff08;线性表的链式存储&#xff09; 代码实例&#xff1a;&#xff08;链表构建&#xff0c;头插尾插&#xff09; LinkedList LinkedList的使用&#xff1a; 1、构造方法 2、操作方法 LinkedList 和 ArrayList 的区别 链表&#xff08;线性表的链式存储…

论文AI疑似度太高?AIGC降痕工具助你快速降低

面对论文降痕的挑战&#xff0c;许多人都感受过其中的困难和挑战。论文里面如果出现“引用”过多的内容&#xff0c;AIGC率高的情况&#xff0c;这个时候怎么办呢&#xff0c;相信大多数的人就是替换同义词或词组、删除冗余的词汇和句子&#xff0c;从而来增加论文的原创性。然…

数仓实践:数据回滚的实现思路

目录 一、什么是数据回滚&#xff1f; 二、数据回滚的作用 1. 增量更新过程中的错误处理 2.维护数据的一致性 3.支持数据同步的可靠性 三、数据回滚的实现思路 1.标识字段的应用 2.数据同步失败的处理 3.数据同步成功后的处理 四、实战案例 在数据同步时&#xff0c;当历史数据…

如何用Claude 3 Sonnet Artifacts实现对数据文件的可视化分析?

如何用Claude 3 Sonnet Artifacts实现对数据文件的可视化分析&#xff1f; Prompt模板&#xff1a; Initial Request: 初始请求&#xff1a; I have uploaded data of the number of Software Engineering Jobs in the US since May 2020. I need different visual creative…

Package hyperref Warning: Ignoring empty anchor on input line 202.

问题 使用https://github.com/yaoyz96/els-cas-templates下载的复杂模板使用overleaf编译会出现警告 解决方案 将cas-dc.cls文件中的代码调换位置&#xff0c;例如将下述代码位置放到文件的最后即可解决问题 \RequirePackage[colorlinks]{hyperref} \colorlet{scolor}{blac…

干货分享 | TSMaster RPC 基础入门:编程指导和使用说明

介绍RPC模块前&#xff0c;我们先浅聊一下RPC的相关说明&#xff0c;以及在什么样的情况下需要了解本文 。 1. RPC 说明 远程过程调用&#xff08;RPC, Remote Procedure Call&#xff09;是一种网络通信协议&#xff0c;使得程序可以调用另一台计算机上的程序或服务&#xff…

# Redis 入门到精通(五)-- redis 持久化(2)

Redis 入门到精通&#xff08;五&#xff09;-- redis 持久化&#xff08;2&#xff09; 一、redis 持久化–save 配置与工作原理 1、RDB 启动方式&#xff1a;反复执行保存指令&#xff0c;忘记了怎么办&#xff1f;不知道数据产生了多少变化&#xff0c;何时保存&#xff1…

多核并行加速 tokenizer

import multiprocessingdef tokenize_text(text):return tokenizer(text, truncationTrue, paddingTrue, max_length256)def parallel_tokenize(texts, num_processesNone):"""使用多核并行处理文本分词"""with multiprocessing.Pool(processesn…

uniapp开发APP,主动连接mqtt,订阅消息

一、安装依赖 通过查阅资料&#xff0c;了解到现在mqtt.js库的最新版本已经是5&#xff0c;但是目前应该mqtt3.0.0版本最为稳定&#xff0c;我项目开发中使用的也是mqtt3.0.0版本 npm install mqtt3.0.0 参考插件&#xff1a;MQTT使用-模板项目 - DCloud 插件市场 参考文档…

鸿蒙Harmony--文本组件Text属性详解

金樽清酒斗十千&#xff0c;玉盘珍羞直万钱。 停杯投箸不能食&#xff0c;拔剑四顾心茫然。 欲渡黄河冰塞川&#xff0c;将登太行雪满山。 闲来垂钓碧溪上&#xff0c;忽复乘舟梦日边。 行路难&#xff0c;行路难&#xff0c;多歧路&#xff0c;今安在&#xff1f; 长风破浪会有…

java中的String 以及其方法(超详细!!!)

文章目录 一、String类型是什么String不可变的原因(经典面试题)String不可变的好处 二、String的常用构造形式1.使用常量串构造2.使用newString对象构造3.字符串数组构造 三、常用方法1. length() 获取字符串的长度2. charAt() 获取字符串中指定字符的值 (代码单元)3. codePoin…

ES快速开发,ElasticsearchRestTemplate基本使用以及ELK快速部署

最近博主有一些elasticsearch的工作&#xff0c;所以更新的慢了些&#xff0c;现在就教大家快速入门&#xff0c;并对一些基本的查询、更新需求做一下示例&#xff0c;废话不多说开始&#xff1a; 1. ES快速上手 es下载&#xff1a;[https://elasticsearch.cn/download/]()这…