面试之快速学习C++11- constexpr以及constexpr和const区别

学习地址: http://c.biancheng.net/view/3730.html

10.constexpr:验证是否为常量表达式

  • 常量表达式: 指的就是由多个(≥1)常量组成的表达式,换句话说,如果表达式中的成员都是常量,那么该表达式就是一个常量表达式。这也意味着,常量表达式一旦确定,其值将无法修改
  • 实际开发中,我们经常会用到常量表达式。以定义数组为例,数组的长度就必须是一个常量表达式。
void testConstexpr() {// 1)int url[10];//正确// 2)int url1[6 + 4];//正确// 3)
//    int length = 6;
//    int url[length];//错误,length是变量
}
  • 我们知道,C++ 程序的执行过程大致要经历编译、链接、运行这 3 个阶段。值得一提的是,常量表达式和非常量表达式的计算时机不同,非常量表达式只能在程序运行阶段计算出结果而常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。
  • 对于用 C++ 编写的程序,性能往往是永恒的追求。那么在实际开发中,如何才能判定一个表达式是否为常量表达式,进而获得在编译阶段即可执行的“特权”呢?除了人为判定外,C++11 标准还提供有 constexpr 关键字。
  • constexpr 关键字的功能是使指定的常量表达式获得在程序编译阶段计算出结果的能力,而不必等到程序运行阶段。C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。
  • 注意⚠️,获得在编译阶段计算出结果的能力,并不代表 constexpr 修饰的表达式一定会在程序编译阶段被执行,具体的计算时机还是编译器说了算

constexpr修饰普通变量:

  • C++11 标准中,定义变量时可以用 constexpr 修饰,从而使该变量获得在编译阶段即可计算出结果的能力。值得一提的是,使用 constexpr 修改普通变量时,变量必须经过初始化且初始值必须是一个常量表达式。举个例子:
void testConstexpr1() {constexpr int num = 1+2+3;int url[num] = {1,2,3,4,5,6};cout << "url[0] = " << url[0];
}
  • 有读者可能发现,将此示例程序中的 constexpr 用 const 关键字替换也可以正常执行,这是因为 num 的定义同时满足“num 是 const 常量且使用常量表达式为其初始化”这 2 个条件,由此编译器会认定 num 是一个常量表达式。注意,const 和 constexpr 并不相同.

constexpr修饰函数:

  • constexpr 还可以用于修饰函数的返回值,这样的函数又称为“常量表达式函数”。
  • 注意,constexpr 并非可以修改任意函数的返回值。换句话说,一个函数要想成为常量表达式函数,必须满足如下 4 个条件。
  1. 整个函数的函数体中,除了可以包含 using 指令、typedef 语句以及 static_assert 断言外,只能包含一条 return 返回语句。
constexpr int display(int x) {int ret = 1 + 2 + x;return ret;
}

注意,这个函数是无法通过编译的,因为该函数的返回值用 constexpr 修饰,但函数内部包含多条语句。

如下是正确的定义 display() 常量表达式函数的写法:

constexpr int testConstexpr3(int x) {//可以添加 using 执行、typedef 语句以及 static_assert 断言return 1 + 2 + x;
}
  1. 该函数必须有返回值,即函数的返回值类型不能是 void。原因很简单,因为通过类似的函数根本无法获得一个常量。
  2. 函数在使用之前,必须有对应的定义语句。我们知道,函数的使用分为“声明”和“定义”两部分,普通的函数调用只需要提前写好该函数的声明部分即可(函数的定义部分可以放在调用位置之后甚至其它文件中),但常量表达式函数在使用前,必须要有该函数的定义。
  3. return 返回的表达式必须是常量表达式,举个例子:
int num = 3;
constexpr int testConstexpr4(int x){return num + x;
}

不行

  1. ⚠️常量表达式函数的返回值必须是常量表达式的原因很简单,如果想在程序编译阶段获得某个函数返回的常量,则该函数的 return 语句中就不能包含程序运行阶段才能确定值的变量。

constexpr修饰类的构造函数:

  • 对于 C++ 内置类型的数据,可以直接用 constexpr 修饰,但如果是自定义的数据类型(用 struct 或者 class 实现),直接用 constexpr 修饰是不行的。举个例子

constexpr struct myType {const char* name;int age;//其它结构体成员
};//报错: Struct cannot be marked constexprvoid testConstexpr5() {constexpr struct myType mt{"a", 1};cout << mt.name << " " << mt.age << endl;
}
  • 当我们想自定义一个可产生常量的类型时,正确的做法是在该类型的内部添加一个常量构造函数。

struct myType {constexpr myType(char *name, const int age):name_(name), age_(age){}char* name_;int age_;
};void testConstexpr5() {constexpr struct myType mt{"a", 1};cout << mt.name_ << " " << mt.age_ << endl;//mt.name_ = "hh"; //报错: Cannot assign to variable 'mt' with const-qualified type 'const struct myType'
}
  • 可以看到,在 myType 结构体中自定义有一个构造函数,借助此函数,用 constexpr 修饰的 myType 类型的 my 常量即可通过编译。

  • 注意⚠️,constexpr 修饰类的构造函数时,要求该构造函数的函数体必须为空且采用初始化列表的方式为各个成员赋值时,必须使用常量表达式

  • 前面提到,constexpr 可用于修饰函数,而类中的成员方法完全可以看做是“位于类这个命名空间中的函数”,所以 constexpr 也可以修饰类中的成员函数,只不过此函数必须满足前面提到的 4 个条件。

class myType1 {
public:constexpr myType1(const char *name, int age) :name_(name), age_(age){}constexpr int getage() const {return age_;}// ⚠️ 这里和网站上的有点不一样,getage必须要在末端加入const , 因为this是const,不加会报错'this' argument to member function 'getage' has type 'const struct myType1', but function is not marked const
private:const char* name_;int age_;
};void testConstexpr6() {constexpr struct myType1 mt{"a", 1};cout <<  " age = " << mt.getage() << endl;//mt.name_ = "hh"; //报错: Cannot assign to variable 'mt' with const-qualified type 'const struct myType'
}
  • 注意,C++11 标准中,不支持用 constexpr 修饰带有 virtual 的成员方法。

constexpr修饰模板函数:

  • C++11 语法中,constexpr 可以修饰模板函数,但由于模板中类型的不确定性,因此模板函数实例化后的函数是否符合常量表达式函数的要求也是不确定的。针对这种情况下,C++11 标准规定,如果 constexpr 修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr 会被自动忽略,即该函数就等同于一个普通函数
struct myType2 {char* name_;int age_;
};template<typename T>
constexpr T display3(T t) {return t;
}
void testConstexpr7() {struct myType2 stu{"hh", 1};//1. 非常量表达式函数, 因为t不是一个常量display3(stu);//2. 是display3(1);
}

11.constexpr和const区别

  • const 用于为修饰的变量添加“只读”属性, 而 constexpr 关键字则用于指明其后是一个常量(或者常量表达式),编译器在编译程序时可以顺带将其结果计算出来,而无需等到程序运行阶段,这样的优化极大地提高了程序的执行效率。
  • C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,
    而将“常量”的语义划分给了新添加的 constexpr 关键字。
    因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,
  • 即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。

结论

相同点:const和consexpr都是用来定义常量的。
不同点:const声明的常量,初始值引用的对象不一定是一个常量;constexpr声明的常量,初始值一定是常量表达式,并且在编译过程就能计算得到结果

  • 还有一个const修饰指针,分为:
    • 顶层const指针自身无法修改
    • 底层const指针可以修改
int i = 10;
int *const p1 = &i; // 底层const:不能修改p1的指向
const int *p2 = &i; // 顶层const:不能修改p2的值
const int *const p3 = &i; // 底层+顶层const
const int &r = i; // 顶层const:不能通过r修改i值

- constexpr修饰指针,仅对指针有效,与指针所指对象无关

 // j的定义必须放在函数体外int j = 30;// 函数体内constexpr int *p1 = &j; // 等价于 int constexpr *p1 = &j;*p1 = 40; // 正确p1 = nullptr; // 错误,constexpr指针无法修改

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

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

相关文章

模型训练之train.py代码解析

题目 作者:安静到无声 个人主页 from __future__ import absolute_import from __future__ import division from __future__ import print_function这段代码使用了Python 2.x的__future__模块来导入Python 3.x的一些特性。在Python 2.x中,使用print语句来输出内容,而在Py…

精准定位:私域流量运营方法解析

随着市场竞争的不断加剧&#xff0c;企业越来越意识到私域流量运营的重要性。与传统的广告推广相比&#xff0c;私域流量运营可以更加精准地定位目标用户&#xff0c;提高用户参与度和忠诚度&#xff0c;从而实现更高的转化率和销售增长。在本文中&#xff0c;我们将深入探讨私…

Modbus TCP转Profibus DP网关modbus tcp报文解析

捷米JM-DPM-TCP网关。在Profibus总线侧作为主站&#xff0c;在以太网侧作为ModbusTcp服务器功能&#xff0c; 下面是介绍捷米JM-DPM-TCP主站网关组态工具的配置方法 2, Profibus主站组态工具安装 执行资料光盘中的安装文件setup64.exe或setup.exe安装组态工具。安装过程中一直…

vscode 设置滑条颜色

1. 默认的滑条是灰黑色的&#xff0c;很难看的清 2. 左下角&#xff0c;打开VS Code 设置功能 3. 输入命令 workbench color&#xff0c;回车 4. 找到工作台&#xff1a;自定义颜色设置&#xff0c;打开设置文件 setting.json 5. 打开配置文件 6. 添加颜色配置 "workben…

C 语言的 getchar() 函数和 putchar() 函数

getchar() 函数和 putchar() 函数是一对字符输入和输出函数. getchar() 作用&#xff1a;get a character from stdin 原型&#xff1a;int getchar( void ); Required Header&#xff1a;<stdio.h> Compatibility&#xff1a;ANSI Return value&#xff1a;return…

暑假刷题第23天--8/7

D-游游的k-好数组_牛客周赛 Round 6 (nowcoder.com)&#xff08;关键--a[1]a[k1]&#xff09; #include<iostream> #include<algorithm> using namespace std; const int N100005; int a[N]; typedef pair<int,int>PII; PII b[N]; void solve(){int n,k,x;…

unraid docker桥接模式打不开页面,主机模式正常

unraid 80x86版filebrowser&#xff0c;一次掉电后&#xff0c;重启出现权限问题&#xff0c;而且filebrowser的核显驱动不支持amd的VA-API 因为用不上核显驱动&#xff0c;解压缩功能也用不上&#xff0c;官方版本的filebrowser还小巧一些&#xff0c;18m左右 安装的时候总是…

C语言每日一题:14《数据结构》复制带随机指针的链表

题目一&#xff1a; 题目链接&#xff1a; 思路一&#xff1a; 找相对位置暴力求解的方法&#xff1a; 1.复制一个新的链表出来遍历老的节点给新的节点赋值&#xff0c;random这个时候不去值。 2.两个链表同时遍历&#xff0c;遍历老链表的时候去寻找相对位置&#xff0c;在遍…

HarmonyOS应用开发的新机遇与挑战

HarmonyOS 4已经于2023年8月4日在HDC2023大会上正式官宣。对广大HarmonyOS开发者而言&#xff0c;这次一次盛大的大会。截至目前&#xff0c;鸿蒙生态设备已达7亿台&#xff0c;HarmonyOS开发者人数超过220万。鸿蒙生态充满着新机遇&#xff0c;也必将带来新的挑战。 HarmonyO…

Java volatile关键字分析

每个线程创建时&#xff0c;JVM会为其创建一份私有的工作内存&#xff08;栈空间&#xff09;&#xff0c;不同线程的工作内存之间不能直接互相访问 JMM规定所有的变量都存在主内存&#xff0c;主内存是共享内存区域&#xff0c;所有线程都可以访问 线程对变量进行读写&#xf…

Rocketmq Filter 消息过滤(TAGS、SQL92)原理详解 源码解析

1. 背景 1.1 Rocketmq 支持的过滤方式 Rocketmq 作为金融级的业务消息中间件&#xff0c;拥有强大的消息过滤能力。其支持多种消息过滤方式&#xff1a; 表达式过滤&#xff1a;通过设置过滤表达式的方式进行过滤 TAG&#xff1a;根据消息的 tag 进行过滤。SQL92&#xff1a…

windows服务器自动重启?

在使用电脑过程中&#xff0c;很多玩家都遇到过系统无故自动重启的情况&#xff0c;实际上引起计算机重启的原因有多种&#xff0c;其中硬件方面原因大致有以下几条。 1、电源是引起系统自动重启的最大嫌疑之一。 劣质的电源不能提供足够的电量&#xff0c;当系统中的设备增多…

【雕爷学编程】MicroPython动手做(33)——物联网之天气预报

天气&#xff08;自然现象&#xff09; 是指某一个地区距离地表较近的大气层在短时间内的具体状态。而天气现象则是指发生在大气中的各种自然现象&#xff0c;即某瞬时内大气中各种气象要素&#xff08;如气温、气压、湿度、风、云、雾、雨、闪、雪、霜、雷、雹、霾等&#xff…

【docker】设置 docker 国内镜像报错问题,解决方案

一、报错&#xff1a; [rootlocalhost ~]# systemctl restart docker Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.二、原因&#xf…

24届近5年江南大学自动化考研院校分析

今天给大家带来的是江南大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、江南大学 学校简介 江南大学&#xff08;Jiangnan University&#xff09;是国家“双一流”建设高校&#xff0c;“211工程”、“985工程优势学科创新平台”重点建设高校&#xff0c;入选…

Windows新版文件资源管理器经常在后台弹出的临时解决方案

禁用组策略自动刷新 运行gpedit.msc找到计算机配置->管理模板->系统->组策略找到 “关闭组策略的后台刷新”启用 参考 https://answers.microsoft.com/en-us/windows/forum/all/windows-11-most-recently-opened-explorer-window/26e097bd-1eba-4462-99bd-61597b5…

C#打开文件对话框、保存文件对话框、字体以及颜色对话框

打开文件对话框 //创建打开文件的对象OpenFileDialog openFileDialog new OpenFileDialog();openFileDialog.Title "请选择要打开的文件";//设置对话框标题openFileDialog.Multiselect true; //设置对话框可以多选openFileDialog.InitialDirectory "C:\Use…

echarts-pie---------3D曲状环形饼图实现!!!

示例&#xff08;参考此处饼图修改https://www.isqqw.com/viewer?id37497&#xff09; 话不多说直接上代码 此套代码可以直接再echarts官网中的此处运行 let selectedIndex ; let hoveredIndex ; option getPie3D([{name: 数学,value: 60,itemStyle: {color: #1890FF,},},{…

【万字长文】SpringBoot整合Atomikos实现多数据源分布式事务(提供Gitee源码)

前言&#xff1a;在最近的实际开发的过程中&#xff0c;遇到了在多数据源的情况下要保证原子性的问题&#xff0c;这个问题当时遇到了也是思考了一段时间&#xff0c;后来通过搜集大量资料与学习&#xff0c;最后是采用了分布式事务来解决这个问题&#xff0c;在讲解之前&#…