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版)》

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • MySql必知必会实战练习(六)游标

    游标主要用于交互式应用,滚动屏幕上的数据,并对数据进行浏览或做出更改看一下下面的例子:输出:由于结果为多行无法显示,这时我们就需要使用游标来操作1.游标基本方法(1)创建游标(2)打开游

    2021年12月29日
    38
  • Collection家族成员

    Collection家族成员

    2021年9月15日
    85
  • noip2012提高组初赛_noip2018提高组初赛解析

    noip2012提高组初赛_noip2018提高组初赛解析Noip2012参赛总结又一年NOIP考完了。刚刚才看了去年自己写的参赛总结,有点后悔考试之前没有看。里面有一句话“NOIP给的数据都是白痴的,一定要多测几组自己的数据,尽管有些数据你相信你的程序一定能过。但往往正是这些数据暴露出了你程序的不足。”对于DAY1的第二题。我想用深搜来做,尽管我知道过不了多少个点,但总比没有好。于是就以很快的速度敲完了深搜,测了两组数据就去做第三题了。离考试

    2022年8月22日
    5
  • resnet讲解_resnet50网络结构详解

    resnet讲解_resnet50网络结构详解1、 RestNet网络1.1、 RestNet网络结构ResNet在2015年被提出,在ImageNet比赛classification任务上获得第一名,因为它“简单与实用”并存,之后很多方法都建立在ResNet50或者ResNet101的基础上完成的,检测,分割,识别等领域里得到广泛的应用。它使用了一种连接方式叫做“shortcutconnection”,顾名思义,shortcut就是“…

    2022年10月7日
    2
  • 三态门(三态缓冲器)的工作原理[通俗易懂]

    三态门(三态缓冲器)的工作原理[通俗易懂]转载于http://www.eeworld.com.cn/mcu/article_2017102035218.html为减少信息传输线的数目,大多数计算机中的信息传输线均采用总线形式,即凡要传输的同

    2022年8月1日
    11
  • CF1153F Serval and Bonus Problem[通俗易懂]

    CF1153F Serval and Bonus Problem[通俗易懂]CF1153F Serval and Bonus Problem

    2022年4月21日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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