首页 > 其他分享 >constexpr的作用(转)

constexpr的作用(转)

时间:2023-07-15 22:12:57浏览次数:24  
标签:std 常量 编译 constexpr 作用 求值 表达式

原文: https://www.zhihu.com/question/274323507

constexpr 的主要用处有

  • 拓宽「常量表达式」的范围
  • 提供显式「要求」表达式编译时(compile-time)求值的方法

为什么要拓宽「常量表达式」的范围,从原本标准库中的很多尴尬之处就可以看出:

比如我们都知道 INT_MAX 是 C 语言的遗物,C++ 则更希望大家使用 std::numeric_limits<int>::max() 来拿 int 型的上限。然而不幸的是,后者是个函数调用而不是常量,使用起来可能需要花更多性能上的心思,没有前者那么自由。

又比如标准文件流,它的构造函数可以带上这样的第二个参数:

std::fstream foo("foo.txt", std::ios::in | std::ios::out);

这个参数是 openmode 类型的,是由实现具体定义的一种 Bitmask 类型。出于类型安全的考虑,通常用枚举值实现而不是整型。但是这样一来就有个问题,同样是写 std::ios::in | std::ios::out,如果用整型的话可以作为常量表达式使用,而为了类型安全考虑换用枚举实现(尤其是重载 | 操作符)后,就再也不可能是常量表达式了。

inline openmode
operator|(openmode lhs, openmode rhs)
{
    return openmode(int_type(lhs) | int_type(rhs));
}

明明是这样简单的函数,可是对它的调用却不是常量表达式。这就让委员会陷入了必须在「类型安全」和「效率」里二选一的尴尬境地。

(也就是说,枚举类型可以保证类型安全,但枚举类型的值不是常量表达式,而整形可以是常量表达式,可以在编译期就进行计算处理,不用在运行的时候计算,效率更高)

标准库里会遇到这样的问题,大家日常使用也会遇到。加之标准委员会很想借此机会把原本标准中对于「常量表达式」(尤其是整型常量表达式)复杂的定义重构简化,引入 constexpr 就很合情合理了。

(此处解释的是把「对某些简单函数的调用」加入「常量表达式」定义的出发点。其它的比如 constexpr 构造函数的用途,套路是一样的,请自行脑补。)

说到这里,「constexpr 函数」并不能和「编译时求值」划等号,它只表达了「这个函数具备这样的能力」

所以才有了 constexpr 的第二个功能:「显式『要求』表达式编译时求值」(这个时候有了它就相当于要求编译时求值,要做到这点就要求给变量初始化的表达时必须是常量表达式。把它放到变量定义前,那么用来初始化这个变量的表达式「必须」是常量表达式,否则报错。

constexpr 函数只有同时满足

  1. 所有参数都是常量表达式
  2. 返回的结果被用于常量表达式(比如用于初始化 constexpr 数据)

才会触发编译时求值。如果只有参数是常量表达式而结果不是,那么是否触发编译时求值取决于具体实现。


C++17 的 constexpr if 虽然严格意义上不是 constexpr 而是 if 的一部分,但既然名字里带 constexpr,也顺便提一下。

constexpr if 的主要用途是简化模板代码(这也意味着除非你是库作者或者模板狂魔,很少会用到)。很多原本需要绕弯借助 SFINAE 或者类型 Tag 来实现,需要拆成 N 个函数的功能,可以借助 constexpr if 写到一个函数里。

(还有一个用途是可以代替类似 #if 的功能,但……我觉得是邪道。)

标签:std,常量,编译,constexpr,作用,求值,表达式
From: https://www.cnblogs.com/tan-wm/p/17557063.html

相关文章

  • 变量、常量、作用域
    变量、常量、作用域变量变量:就是可以变化的量Java是一种强类型语言,每个变量都必须声明其类型Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域typevarName[=value][{,varName[=value]}];//数据类型变量名=值;//可以用逗号隔开来声明多个同类型......
  • 什么是 Rxjs Observable subscribe 方法的副作用
    RxJSObservable是一个强大的用于处理异步或多值的工具。它可以被看作一个事件流,开发人员可以监听这个事件流,并在事件发生时执行一些操作。这就是为什么说Observable的subscribe方法有副作用(sideeffects):因为当开发人员订阅(subscribe)一个Observable时,开发人员实际上是在定......
  • 简单说明DNS、DHCP的主要作用是什么?
    1、DNS(DomainNameSystem,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析);每个IP地址都可以有一个主机名,主机名由......
  • <meta-data/> 标签的作用
    标签应用示例:<activityandroid:name="Settings$SimSettingsActivity"android:label="@string/sim_settings_title"android:icon="@drawable/ic_settings_sim"android:exported="false"a......
  • 学的java,工作用的go?
    学的java,找的java开发,进了公司却在使用go。第一天让拉代码,我以为我拉的是java代码,没想到却是go。当时慌死了,我只听说过go,连helloworld都没有go写过。既来之,则安之,我接下来就是装goland,配环境变量,好在代码跑起来了,这个项目使用go+Gin来进行开发,甚至连数据库都不是我熟悉......
  • 49.instanceof的作用
    49.instanceof的作用?//instanceof运算符用于判断构造函数的prototype属性是否出现在对象的原型链中的任何位置。//实现:functionmyInstanceof(left,right){letproto=Object.getPrototypeOf(left),//获取对象的原型prototype=right.prototype;//获取......
  • jsconfig.json文件作用
    没搞懂具体是个啥,目前知道有两个作用1. 别名路径提示{"compilerOptions":{"target":"esnext",//覆盖vscode的CheckJS选项"checkJs":false,"strict":true,"allowSyntheticDefaultImports":true,&......
  • PostgreSQL技术大讲堂 - 第22讲:CLOG作用与管理
     PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUGPG技术大讲堂。第22讲:CLOG作用与管理内容1:PostgreSQLCLOG概述内容2:CLOG......
  • 现代C++(Modern C++)基本用法实践:六、constexpr编译时计算
    概述constexpr修饰的变量、函数、对象构造函数表示在编译时就可以确定。它经常用来计算一些编译期可以确定常数,和常数组成的表。比如编译时确定10000以内所有的素数,运行时用的时候直接查表。用法举例参考测试项目代码ModernCppTest/modrenc_constexpr.cpp主要内容:constexpr......
  • 注解开发bean作用范围与生命周期管理
     singleton是单例,prototype是多例 ......