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)
上一篇 2026年4月18日 下午1:31
下一篇 2026年4月18日 下午1:37


相关推荐

  • Android——Handler详解

    Android——Handler详解1 简介 Handler 是一套 Android 消息传递机制可以说只要有异步线程与主线程通信的地方就一定会有 Handler 在多线程的应用场景中 将工作线程中需更新 UI 的操作信息传递到 UI 主线程 从而实现工作线程对 UI 的更新处理 最终实现异步消息的处理使用 Handler 消息传递机制主要是为了多个线程并发更新 UI 的同时 保证线程安全 2 相关概念解释 Handler Message MessageQueue LooperAndroi 消息机制 以 Handler 的 sendMes

    2026年3月16日
    2
  • js数组遍历求和

    js数组遍历求和var nbsp num nbsp prompt 请输入数字 用逗号分隔 nbsp nbsp nbsp nbsp varsum eval num replace g nbsp nbsp nbsp alert sum vararr 1 2 3 4 5 eval arr join

    2026年3月26日
    2
  • asp.net中英文转换

    asp.net中英文转换一、中英文切换主要是依靠资源文件(Resources):资源文件名称格式:"页面名称加后缀.resx"      资源文件分为本地[App_LocalResources]和全球化[App_GlobalResources]二、实现过程:  本地资源:1.添加文件夹[App_LocalResources]                    2.创建以.resx结尾的资源文件   …

    2025年8月7日
    6
  • 费舍尔精确检验matlab,Fisher精确检验

    费舍尔精确检验matlab,Fisher精确检验Fisher sExactTestMa simplementat sexactteston tailedtests Otherimpleme m

    2026年3月26日
    2
  • vdbench – 性能压力测试工具

    vdbench – 性能压力测试工具vdbench 是一个 I O 工作负载生成器 通常用于验证数据完整性和度量直接附加 或网络连接 存储性能 vdbench 可以运行在 windows linux 环境 可用于测试文件系统或块设备基准性能

    2026年3月16日
    3
  • 安卓app十大开发框架_web应用开发学什么

    安卓app十大开发框架_web应用开发学什么国内第一本基于Android2.0的经典著作,5大专业社区联袂推荐,权威性毋庸置疑!·Android开发与传统的J2ME开发有何相似与不同?·如何通过SharedPreferences、Files、Network和SQLite等方式高效实现Android数据的存储?又如何通过ContentProviders轻松地实现Android数据的共享?·如何使用OpenCore、MediaPlayer、MediaRecorder方便快速地开发出包含音频和视频等流媒体的丰富多媒体应用?·如何

    2022年5月3日
    46

发表回复

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

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