C++11 constexpr和字面类型:从入门到精通

文章目录

    • 引言
    • 一、constexpr的基本概念与使用
      • 1.1 constexpr的定义与作用
      • 1.2 constexpr变量
      • 1.3 constexpr函数
      • 1.4 constexpr在类构造函数中的应用
      • 1.5 constexpr的优势
    • 二、字面类型的基本概念与使用
      • 2.1 字面类型的定义与作用
      • 2.2 字面类型的应用场景
        • 2.2.1 常量定义
        • 2.2.2 模板参数
        • 2.2.3 函数参数
        • 2.2.2 模板参数
        • 2.2.3 函数参数
        • 2.2.4 枚举类型
      • 2.3 字面类型的使用技巧
        • 2.3.1 使用constexpr
        • 2.3.2 尽量避免运行时计算
        • 2.3.3 常量折叠
    • 三、用户定义字面量
      • 3.1 用户定义字面量的概念
      • 3.2 定义自定义字面量
        • 3.2.1 整数字面量
        • 3.2.2 字符串字面量
      • 3.3 用户定义字面量的优势
    • 四、总结

引言

在C++11标准中,引入了两个非常重要的特性:constexpr和字面类型。这些特性不仅提升了代码的性能,还增强了代码的可读性和可维护性。对于初学者来说,理解和掌握这些特性是迈向高级C++编程的关键一步。本文将详细介绍constexpr和字面类型的基本概念、使用方法以及实际应用场景,帮助你从入门到精通。

一、constexpr的基本概念与使用

1.1 constexpr的定义与作用

constexpr是C++11引入的一个关键字,用于声明可以在编译时计算的常量表达式。它的主要目的是将计算从运行时转移到编译时,从而提高程序的性能。在复杂的系统中,我们常常难以分辨一个初始值是否为常量表达式。而constexpr允许将变量声明为constexpr类型,让编译器来验证变量的值是否是常量表达式。例如:

constexpr int i = 200;
constexpr int j = i + 100;

在这个例子中,ij都是在编译时就能确定值的常量表达式。

1.2 constexpr变量

声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。例如:

constexpr int mf = 0; // 0 是常量表达式
constexpr int limit = mf + 1; // mf + 1 是常量表达式

需要注意的是,如果使用函数返回值初始化constexpr变量,那么该函数必须是constexpr函数。例如:

constexpr int getSize() { return 10; }
constexpr int size = getSize(); // 正确,getSize是constexpr函数

1.3 constexpr函数

constexpr函数是指能用于常量表达式的函数。在C++11中,constexpr函数有一些严格的限制:

  • 函数必须返回一个值,所以它的返回值类型不能是void
  • 函数体必须只有一条语句:return expr,其中expr必须也是一个常量表达式。如果函数有形参,则将形参替换到expr中后,expr仍然必须是一个常量表达式。
  • 函数使用之前必须有定义。
  • 函数必须用constexpr声明。

例如,计算阶乘的constexpr函数:

constexpr int factorial(int n) { return (n <= 1) ? 1 : (n * factorial(n - 1)); 
}

当传入的参数是编译时常量时,该函数会在编译时计算结果。例如:

constexpr int result = factorial(5); // 在编译时计算,值为120

1.4 constexpr在类构造函数中的应用

constexpr还能修饰类的构造函数,即保证传递给该构造函数的所有参数都是constexpr,那么产生的对象的所有成员都是constexpr,该对象也是constexpr对象了,可用于只使用constexpr的场合。例如:

class Test {
public:constexpr Test(int arg1, int arg2) : v1(arg1), v2(arg2) {}
private:int v1;int v2;
};
constexpr Test A(1, 2);
enum e = {x = A.v1, y = A.v2};

需要注意的是,constexpr构造函数的函数体必须为空,所有成员变量的初始化都放到初始化列表中。

1.5 constexpr的优势

使用constexpr带来的好处是多方面的:

  • 性能提升:将计算从运行时转移到编译时,减少了运行时的计算开销。例如,在一些需要频繁计算常量的场景中,使用constexpr可以显著提高程序的运行速度。
  • 类型安全:编译器会对constexpr表达式进行严格的检查,确保其在编译时就能得到计算结果,避免了运行时的错误。
  • 代码可读性:明确地指出哪些变量和函数是用于编译时常量计算的,使代码更加清晰易懂。例如,在定义数组大小时使用constexpr变量,能让其他开发者一眼看出数组大小是在编译时确定的。

C++代码编辑界面

二、字面类型的基本概念与使用

2.1 字面类型的定义与作用

字面类型是指可以用于定义常量的数据类型,其值可以在编译时被求值。在C++中,算术类型、引用、指针和某些类都属于字面类型。使用字面类型可以在编译时确定常量的值,提高程序的性能和安全性。例如:

constexpr int max_size = 100; // 声明一个字面类型的常量

2.2 字面类型的应用场景

2.2.1 常量定义

使用字面类型可以定义编译时确定的常量,如数组大小、循环次数等。例如:

template <int N> 
void print_array(const int (&arr)[N]) { for (int i = 0; i < N; ++i) {std::cout << arr[i] << " "; }std::cout << std::endl; 
}
2.2.2 模板参数

字面类型常量可以作为模板的参数,用于在编译时实例化模板。例如:

template <int N> 
struct Array {int data[N];
};
2.2.3 函数参数

字面类型常量可以作为函数的参数,用于传递编译时已知的常量值。例如:

constexpr int add(int x, int y) { return x + y; 
}
2.2.2 模板参数

字面类型常量可以作为模板的参数,用于在编译时实例化模板。例如:

template <int N> 
struct Array {int data[N];
};
2.2.3 函数参数

字面类型常量可以作为函数的参数,用于传递编译时已知的常量值。例如:

constexpr int add(int x, int y) { return x + y; 
}
2.2.4 枚举类型

使用枚举类型来定义一组编译时已知的常量值。例如:

enum class Color { RED, GREEN, BLUE };

2.3 字面类型的使用技巧

2.3.1 使用constexpr

在定义常量时,使用constexpr关键字以确保它是一个字面类型。例如:

constexpr int result = add(3, 4); // 编译时计算结果
2.3.2 尽量避免运行时计算

使用字面类型可以在编译时进行计算,尽量避免在运行时进行计算,以提高程序性能。例如,在计算数组元素个数时,使用constexpr函数可以在编译时完成计算。

2.3.3 常量折叠

当多个常量表达式相互作用时,编译器会尽可能地将它们合并为一个更简单的常量表达式。例如:

constexpr int a = 2;
constexpr int b = 3;
constexpr int c = a + b; // 编译器会将a + b合并为5

C++代码编辑界面

三、用户定义字面量

3.1 用户定义字面量的概念

在C++11之前,字面量的类型由它们的语法形式决定。C++11引入了用户定义字面量的概念,允许通过定义字面量运算符来扩展这些基本类型的字面量,以支持自定义的类型和行为。例如,我们可以定义一个表示长度的类,并希望能够直接使用字面量来创建这个类的实例,例如,使用15_cm表示15厘米。

3.2 定义自定义字面量

自定义字面量通过定义一个特殊的字面量运算符来实现。这个运算符以operator""为前缀,后跟一个唯一的标识符。根据字面量的类型(整数、浮点数、字符、字符串或布尔值),这个运算符可以有不同的形式。

3.2.1 整数字面量

假设我们想要定义一个表示长度的类,并希望能够直接使用字面量来创建这个类的实例,例如,使用15_cm表示15厘米。首先,定义一个表示长度的类:

class Length { double meters; // 以米为单位
public : explicit Length(double m) : meters(m) { } double toMeters() const { return meters; } 
}; 

然后,定义一个自定义字面量运算符来处理以厘米为单位的长度:

Length operator "" _cm(long double cm) { return Length(cm / 100); // 将厘米转换为米 
}

现在,你可以像这样使用自定义字面量:

auto length = 15.0_cm; // 使用自定义字面量创建Length实例
std::cout << "The length is " << length.toMeters() << " meters.\n"; 
3.2.2 字符串字面量

同样地,我们可以为字符串字面量定义自定义的解析函数。假设我们想要定义一个字面量,用于创建标准化的日期字符串:

std::string operator "" _date(const char* str, size_t len) { // 假设输入的格式为"YYYYMMDD",输出格式为"YYYY-MM-DD" return std::string(str, 4) + "-" + std::string(str + 4, 2) + "-" + std::string(str + 6, 2); 
}

使用这个自定义字面量:

auto date = "20230101"_date; // 使用自定义字面量
std::cout << "Formatted date: " << date << std::endl; 

3.3 用户定义字面量的优势

  • 代码可读性:使代码更加直观,例如在处理时间、长度等单位时,直接使用自定义字面量可以让代码更易理解。
  • 类型安全:避免了因手动转换类型而可能出现的错误。
  • 可维护性:当需求发生变化时,只需要修改字面量运算符的定义,而不需要修改大量的代码。

四、总结

constexpr和字面类型是C++11中非常强大的特性,它们为C++程序员提供了更多的编程选择和优化机会。通过使用constexpr,我们可以将计算从运行时转移到编译时,提高程序的性能;而字面类型和用户定义字面量则增强了代码的可读性和可维护性。在实际编程中,合理运用这些特性可以让我们的代码更加高效、安全和易于理解。希望本文能够帮助你更好地理解和掌握C++11中的constexpr和字面类型,从而提升你的C++编程水平。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84131.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用电脑通过USB总线连接控制keysight示波器

通过USB总线控制示波器的优势 在上篇文章我介绍了如何通过网线远程连接keysight示波器&#xff0c;如果连接的距离不是很远&#xff0c;也可以通过USB线将示波器与电脑连接起来&#xff0c;实现对示波器的控制和截图。 在KEYSIGHT示波器DSOX1204A的后端&#xff0c;除了有网口…

StarRocks 全面向量化执行引擎深度解析

StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计&#xff0c;相比传统行式处理引擎&#xff08;如MySQL&#xff09;&#xff0c;性能可提升 5-10倍。以下是分层拆解&#xff1a; 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…

02 Deep learning神经网络的编程基础 逻辑回归--吴恩达

1.逻辑回归 逻辑回归是一种用于解决二分类任务&#xff08;如预测是否是猫咪等&#xff09;的统计学习方法。尽管名称中包含“回归”&#xff0c;但其本质是通过线性回归的变体输出概率值&#xff0c;并使用Sigmoid函数将线性结果映射到[0,1]区间。 以猫咪预测为例 假设单个…

UDP 与 TCP 的区别是什么?

UDP&#xff08;用户数据报协议&#xff09;与TCP&#xff08;传输控制协议&#xff09;有以下区别&#xff1a; 连接方式 - UDP&#xff1a;无连接&#xff0c;发送数据前不需要建立连接&#xff0c;也不维护连接状态&#xff0c;因此UDP的通信效率较高&#xff0c;适合对实时…

6.计算机网络核心知识点精要手册

计算机网络核心知识点精要手册 1.协议基础篇 网络协议三要素 语法&#xff1a;数据与控制信息的结构或格式&#xff0c;如同语言中的语法规则语义&#xff1a;控制信息的具体含义和响应方式&#xff0c;规定通信双方"说什么"同步&#xff1a;事件执行的顺序与时序…

unipp---HarmonyOS 应用开发实战

HarmonyOS 应用开发实战指南 1. 开篇&#xff1a;为什么选择 HarmonyOS&#xff1f; 最近在开发鸿蒙应用时&#xff0c;发现很多开发者都在问&#xff1a;为什么要选择 HarmonyOS&#xff1f;这里分享一下我的看法&#xff1a; 生态优势 华为手机用户基数大&#xff0c;市场潜…

Python_day48随机函数与广播机制

在继续讲解模块消融前&#xff0c;先补充几个之前没提的基础概念 尤其需要搞懂张量的维度、以及计算后的维度&#xff0c;这对于你未来理解复杂的网络至关重要 一、 随机张量的生成 在深度学习中经常需要随机生成一些张量&#xff0c;比如权重的初始化&#xff0c;或者计算输入…

C++中的数组

在C中&#xff0c;数组是存储固定大小同类型元素的连续内存块。它是最基础的数据结构之一&#xff0c;广泛用于各种场景。以下是关于数组的详细介绍&#xff1a; 一、一维数组 1. 定义与初始化 语法&#xff1a;类型 数组名[元素个数];示例&#xff1a;int arr[5]; // 定义…

three.js 零基础到入门

three.js 零基础到入门 什么是 three.js为什么使用 three.js使用 Three.js1. 创建场景示例 2.创建相机3. 创建立方体并添加网格地面示例 5. 创建渲染器示例 6. 添加效果(移动/雾/相机跟随物体/背景)自动旋转示例效果 相机自动旋转示例 展示效果 实现由远到近的雾示例展示效果 T…

Elasticsearch的写入性能优化

优化Elasticsearch的写入性能需要从多维度入手,包括集群配置、索引设计、数据处理流程和硬件资源等。以下是一些关键优化策略和最佳实践: 一、索引配置优化 合理设置分片数与副本数分片数(Shards):过少会导致写入瓶颈(无法并行),过多会增加集群管理开销。公式参考:分…

FMC STM32H7 SDRAM

如何无痛使用片外SDRAM? stm32 已经成功初始化了 STM32H7 上的外部 SDRAM&#xff08;32MB&#xff09; 如何在开发中无痛使用SDRAM 使它像普通 RAM 一样“自然地”使用? [todo] 重要 MMT(Memory Management Tool) of STM32CubeMx The Memory Management Tool (MMT) disp…

【AIGC】RAGAS评估原理及实践

【AIGC】RAGAS评估原理及实践 &#xff08;1&#xff09;准备评估数据集&#xff08;2&#xff09;开始评估2.1 加载数据集2.2 评估忠实性2.3 评估答案相关性2.4 上下文精度2.5 上下文召回率2.6 计算上下文实体召回率 RAGas&#xff08;RAG Assessment)RAG 评估的缩写&#xff…

VuePress完美整合Toast消息提示

VuePress 整合 Vue-Toastification 插件笔记 记录如何在 VuePress 项目中整合使用 vue-toastification 插件&#xff0c;实现优雅的消息提示。 一、安装依赖 npm install vue-toastification或者使用 yarn&#xff1a; yarn add vue-toastification二、配置 VuePress 客户端增…

C#学习12——预处理

一、预处理指令&#xff1a; 解释&#xff1a;是在编译前由预处理器执行的命令&#xff0c;用于控制编译过程。这些命令以 # 开头&#xff0c;每行只能有一个预处理指令&#xff0c;且不能包含在方法或类中。 个人理解&#xff1a;就是游戏里面的备战阶段&#xff08;不同对局…

开疆智能Profinet转Profibus网关连接CMDF5-8ADe分布式IO配置案例

本案例是客户通过开疆智能研发的Profinet转Profibus网关将PLC的Profinet协议数据转换成IO使用的Profibus协议&#xff0c;操作步骤如下。 配置过程&#xff1a; Profinet一侧设置 1. 打开西门子组态软件进行组态&#xff0c;导入网关在Profinet一侧的GSD文件。 2. 新建项目并…

(三)Linux性能优化-CPU-CPU 使用率

CPU使用率 user&#xff08;通常缩写为 us&#xff09;&#xff0c;代表用户态 CPU 时间。注意&#xff0c;它不包括下面的 nice 时间&#xff0c;但包括了 guest 时间。nice&#xff08;通常缩写为 ni&#xff09;&#xff0c;代表低优先级用户态 CPU 时间&#xff0c;也就是进…

Digital IC Design Flow

Flow介绍 1.设计规格 架构师根据市场需求制作算法模型(Algorithm emulation)及芯片架构(Chip architecture),确定芯片设计规格书(Chip design specification) 原型验证 原型验证(Prototype Validation)通常位于产品开发流程的前期阶段,主要是在设计和开发的初步阶…

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…

LangChain工具集成实战:构建智能问答系统完整指南

导读&#xff1a;在人工智能快速发展的今天&#xff0c;如何构建一个既能理解自然语言又能调用外部工具的智能问答系统&#xff0c;成为许多开发者面临的核心挑战。本文将为您提供一套完整的解决方案&#xff0c;从LangChain内置工具包的基础架构到复杂系统的工程实践。 文章深…

P3156 【深基15.例1】询问学号

P3156 【深基15.例1】询问学号 - 洛谷 数据结构-线性表 #include<bits/stdc.h> using namespace std; int n,m,a[2000005]; int main(){cin>>n>>m;for(int i1;i<n;i)cin>>a[i];//使用数组模拟线性表while(m--){int k;cin>>k;cout<<a[…