constexpr和常量表达式

constexpr和常量表达式常量表达式常量表达式(constexpression)是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。constinta=3;//a是常量表达式constintb=a+1;//b是常量表达式intc=8;//c不是常量表达式,因为c的数据类型是int而不是constintco

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

常量表达式

常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。

const int a = 3;//a是常量表达式
const int b = a+1;//b是常量表达式
int c = 8;//c不是常量表达式,因为c的数据类型是int而不是const int
const int d = get_size();//d不是常量表达式,因为d的值要到运行时才能获取到

字面值类型

常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为字面值类型(literal type)。

字面值类型的概念由Bjarne Stroustrup提出,644号议题(2008.2)将字面值概念的概念定义如下:
    A type is a literal type if it is:
a scalar type; or
a class type with
·a trivial copy constructor,
·a trivial destructor,
·a trivial default constructor or at least one constexpr constructor other than the copy constructor,
all non-static data members and base classes of literal types; or
an array of literal type.
大意是:
一个字面值类型应具有如下特点
是一个标量类型(如整型、浮点型、物理类型和枚举类型)
或是一个具有如下特征的类:
·一个平凡的拷贝构造函数
·一个平凡的析构函数
·一个默认构造函数或者至少一个constexpr类型的构造函数(除拷贝构造函数外),所有非静态的数据成员以及字面值类型的基类
或者一个字面值类型的数组
上面对于字面值类型的定义还牵涉到平凡类型(trivial type),在另一篇博文会讲到。
从定义可以知道,算术类型(整型、浮点型等)、引用、枚举和指针这些简单数据类型都属于字面值类型,此外满足特定条件的类也属于字面值类型。
尽管指针和引用都能定义成constexpr,但它们的初始值却受到严格限制。一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象(如全局变量、静态变量等)。

constexpr变量

在一个复杂的系统中,很难(几乎肯定不可能)分辨一个初始值到底是不是常量表达式。尽管我们可以定义一个const变量并把它的初始值设为我们认为的某个常量表达式,但在实际使用时,尽管要求如此,却常常发现初始值并非常量表达式的情况。因此,对象的定义和使用根本就是两回事儿。

从C++11开始,规定允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。

constexpr int a = 3;//3是常量表达式
constexpr int b = a+1;//b是常量表达式
constexpr int c = get_size();//只有当get_size()是一个constexpr函数时,才是常量表达式,否则语句错误

constexpr指针

需要注意的是,与const关键字不同,一个指针被定义为constexpr,关键字仅对指针有效,与指针所指的对象无关:

const int *p = nullptr;//p是一个指向整型常量的指针
constexpr int *q = nullptr;//q是一个指向整型的常量指针,在这一点上类似于int *const p
指针p和q的类型相差甚远,p是一个指向常量的指针,而q是一个常量指针,其中的关键在于constexpr把它所定义的对象置为了顶层const。
与const指针类似,constexpr指针既可以指向常量也可以指向一个非常量。

int i = 3;
constexpr int *p = &i;

constexpr函数

constexpr函数(constexpr expression)是指能用于常量表达式的函数。定义constexpr函数的方法与其他函数类似,不过要遵循几项约定(根据2008.6的647号议题)。

1.函数体被声明为constexpr
2.非虚函数
3.返回类型及所有形参的类型都必须是字面值类型

4.函数中有且只有一条return语句(在C++14标准中这条规定被删除)

constexpr int new_sz () {return 24;}
constexpr int foo = new_sz();

C++11中关于constexpr函数的定义参考链接:cppreference
在C++14中极大放宽了对constexpr函数的定义限制
执行对constexpr函数的初始化时,编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程中展开,constexpr函数被隐式地指定为内联函数。
特别的,constexpr函数允许返回值并非一个常量:
constexpr size_t scale (size_t cnt) {return new_sz()*cnt}//如果arg是常量表达式,则scale(arg)也是常量表达式
int arr[scale(2)];//正确,scale(2)是常量表达式
constexpr函数不一定返回常量表达式,返回值可以为空(return ;)。

和其它函数不一样,内联函数和constexpr函数可以在程序中多次定义。毕竟,编译器要想展开函数仅有函数声明时不够的,还需要函数的定义。不过,对于某个给定的内联函数或者constexpr函数来说,它的多个定义必须完全一致。基于这个原因,内联函数和constexpr函数通常定义在头文件中。

constexpr构造函数

尽管构造函数不能是const的,但是字面值常量类的构造函数可以是constexpr函数。事实上,一个字面值常量类必须至少提供一个constexpr构造函数。
constexpr构造函数可以声明成=default的形式(或者是删除函数的形式)。否则,constexpr构造函数就必须既符合构造函数的要求(意味着不能包含返回语句),又符合constexpr函数的要求(意味着它能拥有的唯一可执行语句就是返回语句)。综合这两点可知,constexpr构造函数体一般来说应该是空的,因此对函数成员的初始化必须放在初始化列表中。

constexpr构造函数必须初始化所有数据成员,constexpr构造函数保证了传递给它的所有参数都是constexpr类型的,产生的对象的所有成员也都是constexpr。



本文部分内容摘自《C++ Primer(第5版)》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/187828.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • JVM调优工具总结

    JVM调优工具总结一、jps:虚拟机进程状况工具它可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(MainClass,main()函数所在的类)名称以及正在运行的本地虚拟机唯一ID(LVMID);它是使用率最高的一个JDK命令行工具,因为其他的命令行工具都需要输入查询到的ID来确定要监控的是哪一个虚拟机进程。命令格式:jps[options][hostid]选项作用-q只…

  • 在Windows上安装MySQL教程总结[通俗易懂]

    在Windows上安装MySQL教程总结[通俗易懂]MySQL数据库环境搭建步骤总结

  • FPGA之SDRAM控制器设计(一)

    MT48LC128M4A2–32Megx4x4banks是512MSRAM,总体概述如下图分别从上电初始化,刷新,写,读四个部分进行设计,此外还包含主控状态机,一个顶层。1:上电初始化整体架构:从控制器到要控制的芯片可以分成20位的bus总线,时钟线sdr_clk,数据总线DQ以及DQM。上电时候主要是对bus总线的高4位也就是sdr_cmd进行配置。也就是要做的第一步,比较简单就是对sdr_cmd进行几次操作。其中注意在逻辑设计时候输出的sdr_clk时钟要和..

  • win7系统的IIS服务器如何解除上传200k限制

    win7系统的IIS服务器如何解除上传200k限制

  • 360天擎无密码退出和卸载一样吗_奇安信天擎退出密码

    360天擎无密码退出和卸载一样吗_奇安信天擎退出密码无密码退出删除配置(360Safe\EntClient\conf\EntBase.dat)**注:**删除时提示权限不够无法删除,使用360自带的文件粉碎机将文件粉碎即可无密码退出360天擎(重新打开程序时EntBase.dat会再次生成)修改配置(将EntBase.dat中uipass、qtpass两项值置空)**注:**修改时提示权限不够无法修改,需先关闭【设置】【防护中心】【自我保护】功能卸载只能通过修改配置(将EntBase.dat中uipass、qtpass两项值置空)

  • apache2虚拟主机实现一个服务器绑定多个域名[通俗易懂]

    apache2虚拟主机实现一个服务器绑定多个域名[通俗易懂]1.apache2的配置首先要配置好apache2,如果未配置,请参考我之前的博文:lamp的配置2.域名的解析将全部域名的www和@的A记录解析到云服务器的IP3.虚拟主机的配置1.配置httpd.conf如果etc/httpd/conf/httpd.conf存在,则配置此httpd.conf如果etc/httpd/conf/httpd.conf不存在,此时需要我们在/etc/apache2下

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号