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

news2025/6/10 12:12:23

文章目录

    • 引言
    • 一、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.coloradmin.cn/o/2406602.html

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

相关文章

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用

摘要 神经影像技术对医学科学产生了深远的影响&#xff0c;推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下&#xff0c;基于神经血管耦合现象的多模态神经影像方法&#xff0c;通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里&#xff0c;本研…

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)

漏洞概述 漏洞名称&#xff1a;Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号&#xff1a;CVE-2023-25194 CVSS评分&#xff1a;8.8 影响版本&#xff1a;Apache Kafka 2.3.0 - 3.3.2 修复版本&#xff1a;≥ 3.4.0 漏洞类型&#xff1a;反序列化导致的远程代…

Copilot for Xcode (iOS的 AI辅助编程)

Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot&#xff0c;它能根据上下文补全代码&#xff0c;快速生成常用…

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:

RabbitMQ 各类交换机

为什么要用交换机&#xff1f; 交换机用来路由消息。如果直发队列&#xff0c;这个消息就被处理消失了&#xff0c;那别的队列也需要这个消息怎么办&#xff1f;那就要用到交换机 交换机类型 1&#xff0c;fanout&#xff1a;广播 特点 广播所有消息​​&#xff1a;将消息…

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…

欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!

多连接 BLE 怎么设计服务不会乱&#xff1f;分层思维来救场&#xff01; 作者按&#xff1a; 你是不是也遇到过 BLE 多连接时&#xff0c;调试现场像网吧“掉线风暴”&#xff1f; 温度传感器连上了&#xff0c;心率带丢了&#xff1b;一边 OTA 更新&#xff0c;一边通知卡壳。…

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…

OPENCV图形计算面积、弧长API讲解(1)

一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的API…

spring boot使用HttpServletResponse实现sse后端流式输出消息

1.以前只是看过SSE的相关文章&#xff0c;没有具体实践&#xff0c;这次接入AI大模型使用到了流式输出&#xff0c;涉及到给前端流式返回&#xff0c;所以记录一下。 2.resp要设置为text/event-stream resp.setContentType("text/event-stream"); resp.setCharacter…

二叉树-144.二叉树的前序遍历-力扣(LeetCode)

一、题目解析 对于递归方法的前序遍历十分简单&#xff0c;但对于一位合格的程序猿而言&#xff0c;需要掌握将递归转化为非递归的能力&#xff0c;毕竟递归调用的时候会调用大量的栈帧&#xff0c;存在栈溢出风险。 二、算法原理 递归调用本质是系统建立栈帧&#xff0c;而非…

【技巧】dify前端源代码修改第一弹-增加tab页

回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码&#xff0c;在知识库增加一个tab页"HELLO WORLD"&#xff0c;完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…

Java设计模式:责任链模式

一、什么是责任链模式&#xff1f; 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09; 是一种 行为型设计模式&#xff0c;它通过将请求沿着一条处理链传递&#xff0c;直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者&#xff0c;…

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…

云原生时代的系统设计:架构转型的战略支点

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、云原生的崛起&#xff1a;技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深&#xff0c;传统的 I…

python可视化:俄乌战争时间线关键节点与深层原因

俄乌战争时间线可视化分析&#xff1a;关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一&#xff0c;自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具&#xff0c;系统分析这场战争的时间线、关键节点及其背后的深层原因&#xff0c;全面…

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…