当前位置: 首页 > news >正文

(C++20) consteval立即函数

文章目录

  • 由来
  • consteval立即函数
    • 上下文的常量性质
    • lambda表达式
  • 编译期间确定
    • 无法获取函数指针
    • 查看汇编
  • END

由来

在C++11中推出了constexpr使得对象或者函数能够具有常量性质并能在编译器确定。但是对于constexpr修饰的函数来说,无法保证严格的在编译器确定。

下面这段代码,fun1正常编译运行,但是到了fun2就会编译失败。

constexpr int square(int x) {return x * x;
}void fun1(int x) {square(10);square(x);
}void fun2(int x) {constexpr int num1 = square(10);// error: 'x' is not a constant expression// constexpr int num2 = square(x);
}int main(int argc, char** argv) {
}

consteval立即函数

consteval 说明符 (C++20 起) - cppreference.com

为了能够强制在编译期间计算,C++20推出了consteval关键字用于修饰函数。强制要求该函数必须表现为常量性质

consteval int square(int x) {return x * x;
}

上下文的常量性质

编译器会自动检测上下文的常量性质,因此下面这段代码也是可性的。

constexpr int square(int x) {return x * x;
}// constexpr函数 调用 constexpr函数
constexpr int re_square(int x) {return square(square(x));
}int main() {// 上下文常量性质const int     x    = 10;constexpr int num1 = square(x);constexpr int num2 = re_square(x);
}

lambda表达式

说到函数怎么能少得了lambda函数,在参数后添加关键字即可。

int main() {auto square = [](int x) constexpr { return x * x; };const int     x   = 10;constexpr int num = square(x);
}

编译期间确定

无法获取函数指针

新手可能不太了解什么叫编译期间确定。

这里举个例子,一般函数我们可以获取它的地址,并赋到一个函数指针上。

但是consteval函数不行。因为它根本不会产生函数实例!

int fun1(int x) {return x + 10;
}consteval int fun2(int x) {return x + 10;
}int main() {int (*funPtr1)(int) = &fun1;// error: taking address of an immediate function ‘consteval int fun2(int)’// int (*funPtr2)(int) = &fun2;
}

查看汇编

再具体的我们来查看汇编代码,便会一目了然!

现在有如下的代码:

int funnnnnn000000000000000000000000(int x) {return x + 10;
}constexpr int funnnnnn111111111111111111111111(int x) {return x + 10;
}consteval int funnnnnn222222222222222222222222(int x) {return x + 10;
}int main() {const int x = 10;funnnnnn000000000000000000000000(x);funnnnnn111111111111111111111111(x);funnnnnn222222222222222222222222(x);
}

环境与指令:

gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 
g++ -std=c++20 test.cpp -S

生成的汇编代码:

	.file	"test.cpp".text.globl	_Z32funnnnnn000000000000000000000000i.type	_Z32funnnnnn000000000000000000000000i, @function
_Z32funnnnnn000000000000000000000000i:
.LFB0:.cfi_startprocendbr64pushq	%rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq	%rsp, %rbp.cfi_def_cfa_register 6movl	%edi, -4(%rbp)movl	-4(%rbp), %eaxaddl	$10, %eaxpopq	%rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size	_Z32funnnnnn000000000000000000000000i, .-_Z32funnnnnn000000000000000000000000i.section	.text._Z32funnnnnn111111111111111111111111i,"axG",@progbits,_Z32funnnnnn111111111111111111111111i,comdat.weak	_Z32funnnnnn111111111111111111111111i.type	_Z32funnnnnn111111111111111111111111i, @function
_Z32funnnnnn111111111111111111111111i:
.LFB1:.cfi_startprocendbr64pushq	%rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq	%rsp, %rbp.cfi_def_cfa_register 6movl	%edi, -4(%rbp)movl	-4(%rbp), %eaxaddl	$10, %eaxpopq	%rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1:.size	_Z32funnnnnn111111111111111111111111i, .-_Z32funnnnnn111111111111111111111111i.text.globl	main.type	main, @function
main:
.LFB3:.cfi_startprocendbr64pushq	%rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq	%rsp, %rbp.cfi_def_cfa_register 6subq	$16, %rspmovl	$10, -4(%rbp)movl	$10, %edicall	_Z32funnnnnn000000000000000000000000imovl	$10, %edicall	_Z32funnnnnn111111111111111111111111imovl	$0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE3:.size	main, .-main.ident	"GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0".section	.note.GNU-stack,"",@progbits.section	.note.gnu.property,"a".align 8.long	1f - 0f.long	4f - 1f.long	5
0:.string	"GNU"
1:.align 8.long	0xc0000002.long	3f - 2f
2:.long	0x3
3:.align 8
4:

可见普通函数和constexpr函数都可以在汇编函数中展现,但是consteval函数并没有,这也正解释了为什么为什么不能获取函数指针。




END

相关文章:

  • 安卓搜索框,EditText,SearchView
  • ubuntu22.04 鼠标乱动原因-关闭触屏和触摸版
  • python opencv 演示示例
  • IntelliJ IDEA安装使用教程
  • electron windows robotjs 安装教程
  • Rust语言入门教程(六) - 字符串类型
  • WebSocket 是什么原理?为什么可以实现持久连接?
  • 物流实时数仓ODS层——Mysql到Kafka
  • vue中.sync修饰符与$emit(update:xxx)双向数据绑定
  • Learn the architecture - Understanding Armv9-A trace
  • gRPC之grpc负载均衡(resolver)
  • STM32USART+DMA实现不定长数据接收/发送
  • Node.js 的 os 模块介绍
  • 【多传感器融合】BEVFusion: 激光雷达和视觉融合框架 NeurIPS 2022
  • TemplateHit中提取query和hit比对上序列索引的映射字典
  • 《剑指offer》分解让复杂问题更简单
  • echarts的各种常用效果展示
  • exports和module.exports
  • Java面向对象及其三大特征
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • nodejs:开发并发布一个nodejs包
  • Vue 动态创建 component
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 从重复到重用
  • 给Prometheus造假数据的方法
  • 基于遗传算法的优化问题求解
  • 记一次删除Git记录中的大文件的过程
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 扑朔迷离的属性和特性【彻底弄清】
  • 应用生命周期终极 DevOps 工具包
  • 优化 Vue 项目编译文件大小
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • $().each和$.each的区别
  • (libusb) usb口自动刷新
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (六)Hibernate的二级缓存
  • (十二)springboot实战——SSE服务推送事件案例实现
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .NET Project Open Day(2011.11.13)
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • @EnableAsync和@Async开始异步任务支持
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [Android]一个简单使用Handler做Timer的例子
  • [AutoSar]BSW_Com02 PDU详解
  • [Avalon] Avalon中的Conditional Formatting.
  • [CSS3备忘] transform animation 等
  • [DP 训练] Longest Run on a Snowboard, UVa 10285
  • [ES-5.6.12] x-pack ssl