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)


相关推荐

  • spring cloud之 hello world和eurake介绍及eurake使用

    spring cloud之 hello world和eurake介绍及eurake使用一.springcloud之helloworld1.两个微服务,分别是用户和订单,其中用户是微服务提供者,订单是微服务消费者2.首先建一个工程,里面有两个module:prvoider-user和comsumer-ordercomsumer-user配置文件:prvoider-order配置文件:用spring提供的RestTemplate访问rest…

  • Python如何将字符串分割成单个字符,并形成一个list?

    Python如何将字符串分割成单个字符,并形成一个list?一个字符串可以看做是一个list具体操作如下>>>a="这是一段话">>>a[0]’这’>>>list(a)[‘这’,’是’,’一’,’段’,’话’]>>>forxina: print(x) 这是一段话>>>所以

  • intellij+idea+激活码【最新永久激活】2022.03.05

    (intellij+idea+激活码)最近有小伙伴私信我,问我这边有没有免费的intellijIdea的激活码,然后我将全栈君台教程分享给他了。激活成功之后他一直表示感谢,哈哈~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • Cocos2D-X学习笔记 3 从一个场景切换到还有一个场景

    Cocos2D-X学习笔记 3 从一个场景切换到还有一个场景

  • Matlab fitrsvm自带支持向量回归[通俗易懂]

    Matlab fitrsvm自带支持向量回归[通俗易懂]简介fitrsvm在中低维预测变量数据集上训练或交叉验证支持向量机(SVM)回归模型。fitrsvm支持使用内核函数映射预测变量数据,并支持通过二次编程实现目标函数最小化。要在高维数据集(即包含许多预测变量的数据集)上训练线性SVM回归模型,请改用fitrlinear。用法Mdl=fitrsvm(Tbl,ResponseVarName)返回使用表Tbl中的自变量值和表中对应变量名…

  • iOS跑步软件开发-从无到有

    iOS跑步软件开发-从无到有前言经过两个多月的开发与调试,全民星跑1.0.1终于上线了,首先要感谢曲总和洛洛爱吃肉的技术支持.全民星跑作为一个以跑步计步为主要功能的软件,骚栋在开发过程中实在是遇到了不少的坑,这篇博客会分为加速仪计步和跑步计步两个模块来说明,不过有一点我想先声明,因为人力资源有限,所以可能在计步的逻辑上跟不上咕咚或者是Keep这些大厂,望各位看官见谅.????????????功能规划一个App如何统计一个人的运动?这里主要有两种方式,一种是使用陀螺仪(或是加速仪)获取手机各个方向的加速度来统计用户的

发表回复

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

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