现代C++实践100练:吃透C++新特性constexpr

C++模板编程实战:从泛型思想到智能指针实现 泛型编程是一种编程范式,其核心思想是编写与具体数据类型无关的通用代码,以此提升代码的复用性和可维护性。其原理在于通过类型参数化,让编译器在编译时根据实际使用的类型生成特化代码,从而实现编译时多态。这项技术的核心价值在于能够在保证类型安全的前提下,避免代码冗余,同时不引入运行时开销。它在构建通用库、数据结构和算法时尤为重要,例如C++标准模板库(STL)中的容器和算法就广泛依赖于此。在实际应用中,泛型编程是构建如智能指针等资源管理工具的基础。本文以C++模板为具体载体,深入探讨了函数模板、类模板以及变参模板的 阅读详情

在讲这个问题之前,我想先说下本文的风格,这也是我写作的风格,通常我不会像教科书一般上来就直说概念和道理,我喜欢用已知,大家可以理解的问题去引入一个知识,这是我自己的学习方法,也希望介绍给大家。

例如本文,很多人可能不知道constexpr,也不知道为什么要引入它,但是大家都知道const,通过const引入,就往往容易接受的多。

本文你可以了解到什么

了解constexpr这一优秀的新特性

你可以知道我们为什么建议使用常量constexpr,它比const优秀?

const

const是一个C语言的关键字,它限定一个变量不允许被改变。

在之前const就是被作为常量使用的,现在多了一个constexpr是不是多此一举呢?

我们继续来看,了解一下const的作用:

(1)可以定义const常量,具有不可变性。

例如:const int Max=100; Max++会产生错误;

(2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患。

例如: void f(const int i) { …} 编译器就会知道i是一个常量,不允许修改;

(3)可以避免意义模糊的数字出现,同样可以很方便地进行参数的调整和修改。 同宏定义一样,可以做到不变则已,一变都变!

(4)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。

(5) 可以节省空间,避免不必要的内存分配。

const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。

从上面几个地方看const就是常量,那么我们进行一个小测试:

const int len = 5;

int a[len];

可能在现在编译器使用,它都是不报错的,因为已经经过了编译器优化,但是在老版本的编译器中往往会报错!

这是因为 C++ 标准中数组的长度必须是一个常量表达式,而对 于 len而言,这是一个 const 常数,而不是一个常量表达式,因此(即便这种行为在大部分编译器中 都支持,但是)它是一个非法的行为。

如果你想知道,这到底是为什么,可以看下这段我的总结,但是我不保证它百分百正确!

数组的长度需要常量定义,像是5、6、7这种肯定是常量,只读;因为常量是被编译器放在内存中的只读区域,当然也就不能够去修改它。

而const变量实在内存中存在的,只不过编译器不允许它被修改,毕竟const定义的变量,虽然被叫做常量,但是更细一点是被叫做”常值变量“,当作变量看待。

constexpr:常量表达式

constexpr(常量表达式):是指值不会改变并且在编译过程就能得到计算结果的表达式。

常量表达式的优点是将计算过程转移到编译时期,那么运行期就不再需要计算了,程序性能也就提升了。

const好用,但是在某些情况下,我们还是会被它所谓的”常量“,给迷惑,产生错误用法,那既然如此,到底有没有真正的常量定义呢!

答案:有的。

C++11 提供了 constexpr 让用户显式的声明函数或对象构造函数在编译期会成为常量表达式,这 个关键字明确的告诉编译器应该去验证 constexpr定义的值在编译期就应该是一个常量表达式。

constexpr int len = 5;

int a[len];

此时使用合法!

constexpr定义函数

constexpr int Length_Constexpr()
{
	return 5;
}

char arr_2[Length_Constexpr() + 1]; // 合法

constexpr返回值也是常量!

但是constexpr函数和正常函数肯定是不一样的,因为它需要在编译期做事,需要有一定的使用限制!

从C++11开始,constexpr函数不仅可以返回常量,还可以进行递归操作。

constexpr int fibonacci(const int n) 
{
return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
}

从 C++14 开始,constexpr 函数可以在内部使用局部变量、循环和分支等简单语句。

constexpr int fibonacci(const int n) 
{
if(n == 1) return 1;
if(n == 2) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}

编译期的优化

C++ 本身已经具备了常量表达式的概念,比如 1+2, 3*4 这种表达式总是会产生相同的结果并且没 有任何副作用。如果编译器能够在编译时就把这些表达式直接优化并植入到程序运行时,将能增加程序的性能。

性能实测

constexpr int Calculate1 (int x, int y)
{
    return x * y * 32 / 14;
}
int Calculate2 (int x, int y)
{
    return x * y * 32 / 14;
}
int main()
{
    uint64_t start, end;
    start = GetMicroSeconds();
    for(int i = 0;i < 100000; i++)
{
//也可以换成const修饰,也是常量表达式
        constexpr int ret = Calculate1 (11, 12); 
    }
    end = GetMicroSeconds();
    cout<<"spend time: "<<end-start<<" us"<<endl;
       
    start = GetMicroSeconds();
    for(int i = 0;i < 100000; i++)
    {
//不能用constexpr修饰,不是常量表达式,会编译报错
        int ret = Calculate2 (11, 12);
    }
    end = GetMicroSeconds();
    cout<<"spend time: "<<end-start<<" us"<<endl;
    return 0;
}

这段代码比较简单,一个常量表达式和一个非常量表达式,都进行相同的计算,都循环10w次,然后记录各自的总耗时,单位是微秒。

打印结果如下:

spend time: 182 us
spend time: 929 us

大家可以看到,接近5倍的性能差别,这要是发生在高性能开发中,将是一次不错的性能提升。

使用总结

语义上来说:

如果变量用constexpr修饰,那么变量也具有const的特性;如果变量用const修饰,不能说明变量具有constexpr的特性。从语义上讲,const更像是“read only”,而constexpr更像是“const”。

一般来说,当你认为变量一定是常量表达式,那就把它声明成constexpr类型吧。

参考资料

现代C++之constexpr

const和constexpr还在傻傻分不清?

C++游戏开发:基于std::chrono实现精准帧率控制与动画计时 在实时应用和游戏开发中,时间管理是确保程序稳定运行的核心基础。其原理在于通过高精度计时器对时间间隔进行精确测量,从而实现对程序执行节奏的精准控制。这项技术的核心价值在于保障了动画的流畅性、物理模拟的稳定性以及游戏逻辑的确定性,是构建健壮交互体验的基石。其应用场景广泛覆盖了游戏引擎开发、实时模拟系统和图形应用程序。本文聚焦于C++标准库中的std::chrono模块,深入探讨如何利用其提供的类型安全时钟与时间段抽象,来构建游戏引擎中至关重要的帧率控制与动画计时两大模块,解决游戏循环中时间步长管理与动画插值的关 阅读详情

相关推荐

C++11核心特性解析:右值引用、智能指针与并发编程实战

在C++编程中,资源管理和并发编程是提升代码性能与安全性的关键。传统C++依赖手动内存管理和平台特定的多线程API,容易引发内存泄漏和数据竞争等问题。C++11通过引入右值引用与移动语义,实现了高效的资源转移,避免了不必要的深拷贝开销。智能指针(如unique_ptr、shared_ptr)基于RAII机制,自动管理内存生命周期,显著提升了代码的健壮性。标准线程库(std::thread、std::mutex、std::atomic)提供了可移植的并发编程支持,简化了多线程开发。这些特性共同构成了现代C++

weixin_34198881的博客 397

【现代C++】constexpr用法

现代C++中的constexpr关键字允许在编译时进行表达式求值,从而提高程序的性能和安全性。这项特性自C++11引入,并在后续的C++14和C++17标准中得到增强。以下是constexpr。

karl2000的专栏 713

C++函数设计进阶:缺省参数与函数重载实战指南

在C++编程中,函数是构建程序的基础模块。其设计质量直接影响代码的可读性、可维护性和复用性。为了提升函数接口的灵活性,C++提供了缺省参数和函数重载两大核心特性。缺省参数通过在函数声明中为参数指定默认值,使得调用时可以省略部分参数,从而简化高频调用并保持向后兼容性。函数重载则允许在同一作用域内定义多个同名函数,通过不同的参数列表(类型、数量或顺序)来区分,实现对相似操作语义的统一命名,降低API学习成本。这两项技术共同体现了C++‘零开销抽象’的设计哲学,能有效解决工程中常见的接口冗余问题,例如配置读取、日

weixin_33725270的博客 330

深入探讨 C++ 中的 `constexpr` 函数及其限制

constexprconstexpr函数是 C++ 中一个强大的特性,它允许程序员在编译时计算常量表达式,从而提高程序的性能和可读性。通过合理使用constexpr函数,程序员可以编写出更高效、更简洁的代码。然而,使用constexpr函数时也需要注意其限制,确保代码的正确性和可移植性。在现代 C++ 编程中,掌握constexpr函数的使用将极大地提升你的编程能力和代码质量。希望本文能帮助你更好地理解和应用 C++ 中的constexpr函数。

铭渊老黄 1539

C++模板编程:从template<typename T>入门到实战应用

泛型编程是现代C++的核心范式之一,它通过参数化类型实现了代码的通用性和复用性。其基本原理是允许开发者编写与具体类型无关的算法和数据结构,编译器在编译时根据实际使用的类型自动生成特化版本。这一技术极大地提升了代码的灵活性和可维护性,是构建标准模板库(STL)等通用组件的基础。在实际工程中,泛型编程广泛应用于容器、算法库、智能指针等场景,有效解决了代码冗余问题。本文以C++的模板机制为切入点,深入解析了函数模板和类模板的实现,并探讨了模板特化、SFINAE等高级特性在资源管理中的应用,例如实现一个类似std:

weixin_33857679的博客 858

C++模板与STL深度解析:从泛型编程到高效实战应用

泛型编程是一种将算法从特定数据结构中抽象出来的核心编程范式,它通过编写不依赖具体数据类型的通用代码来提升代码复用性。在C++中,这一思想通过模板技术得以实现,允许开发者创建可处理多种数据类型的函数和类。模板的技术价值在于其能够实现编译时多态,生成类型安全且高度优化的代码,从而避免运行时开销。基于模板构建的标准模板库(STL)是这一思想的集大成者,它将通用算法与数据结构分离,通过迭代器连接,提供了如vector、map、sort等高效组件,广泛应用于系统软件、游戏开发、高频交易等对性能有严苛要求的场景。理解模

weixin_33841722的博客 270

C++20:constexpr、consteval和constinit

C++从C++11开始支持constexpr,直到C++20对constexpr的完整支持,constexpr标准化跨越了13年,由4个标准实现。C++20也是最接近最初语言设计模板的版本,但是constexpr的设计其实也不够严谨,所以 C++20 引入了 consteval;由于constexpr仅能实现编译时常量求值,为了解决编译时非常量求值问题,C++20又引入了constinit关键字。本文详细介绍constexpr/constinit/consteval支持历史和版本。

一鸣惊人的博客 3719

C++核心概念全解析:内存模型、引用、类与文件操作实战指南

在C++编程中,内存管理是程序运行的基石,理解内存分区模型(栈区、堆区、全局区、代码区)是掌握变量生命周期和作用域的关键。通过引用机制,程序员可以高效安全地传递参数,避免不必要的拷贝开销,提升代码性能。面向对象编程的核心在于类与对象的设计,封装、继承和多态三大特性构建了可复用、易维护的代码结构。文件操作则是连接内存数据与持久化存储的桥梁,实现数据的长期保存与读取。本文聚焦C++核心知识体系,结合内存管理、引用优化及类设计等热词,深入探讨如何将这些基础概念串联,构建健壮的C++应用程序,适用于系统开发、性能优

weixin_30394669的博客 358

C++总结:C++中的const和constexpr

C++总结:C++中的const和constexpr 2014-02-18 15:31付哲 阅读(14334) 评论(0)编辑收藏 C++中的const可用于修饰变量、函数,且在不同的地方有着不同的含义,现总结如下。 const的语义 C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象的常量性的操作都视为error。 对象的常量性可以分为两种:物理常量性(即每个bit都不可改变)和逻辑常量性(即对象的表现保持不变)。C++中采用的是...

u010843408的专栏 811

人工智能在高中教育中的应用现状剖析与挑战应对

人工智能在高中教育中的应用现状剖析与挑战应对

燕鹏 1340

基于STM32F103C8T6的红外循迹避障小车

编程思路:控制核心板IO口的电平(即电机驱动模块的AIN1,AIN2,BIN1,BIN2)从而控制AO1、AO2、BO1、BO2的电平高低,进而控制电机使其正转、反转、不转。由于单纯地拉高拉低电平只能让电机在转与不转的状态切换,故决定利用TIM4的两个通道分别产生两路PWM信号来控制电机速度,四个电机两个一组,同一侧的两个连接在同一个PWM上。(#include "dianji.h"文件中同时写了对循迹模块引脚的初始化)

weixin_48743503的博客 1万+

SLAM练习题(二)—— C++新特性:简化循环、自动类型推导、列表初始化、lambda函数

从零手写SLAM笔记 文章目录简单循环、自动类型推导、列表初始化lambda函数sort()函数 简单循环、自动类型推导、列表初始化 题目:请使用C++新特性改写以下函数。该函数功能:将一组无序的坐标按照“Z”字形排序,并输出。 题目如下图所示: 知识点:熟悉C++新特性(简化循环、自动类型推导、列表初始化、lambda函数/*) #include <opencv2/opencv.hpp> #include <iostream> #include <vector> .

图像处理、SLAM、PCL、OpenCV爱好者 535

汇川AM系列后台安全管理与用户权限的设置方法

汇川AM系列后台安全管理与用户权限的设置方法。

viixin的博客 8461

C++11核心特性解析:从auto到智能指针的现代C++编程实践

在C++编程语言的发展历程中,类型推导和内存管理是两个基础且关键的技术概念。类型推导允许编译器自动推断变量类型,减少代码冗余并提升可读性;而内存管理则关乎程序的安全性与性能,传统手动管理方式容易导致内存泄漏和悬垂指针。C++11通过引入auto关键字和智能指针,系统性地解决了这些问题,其技术价值在于显著提升了代码的简洁性、安全性和可维护性。这些特性广泛应用于系统软件开发、高性能计算和大型项目构建等场景,使得C++能够更好地适应现代软件工程的需求。本文聚焦于C++11的auto类型推导与智能指针等核心机制,深

weixin_30904593的博客 481

cocos creator接入微信登陆sdk ios篇

cocos creator接入微信登陆sdk ios篇 背景已经在Android篇里面交代过了,有兴趣的朋友可以再看看Android篇 步骤 去微信开放平台下载ios平台所需要的sdk 在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id 在“info”标签栏的“LSApplicationQueriesSchemes“添加weixin 将SDK文件中...

凤小鹿的博客 6362

OpenClaw + Antigravity + 飞书完整部署教程

在 Linux 服务器上部署 OpenClaw,使用 Antigravity 本地代理 AI 模型,并接入飞书实现 24 小时在线 AI 助手。

Maynor的博客 1788

STL堆算法深度解析:从隐式二叉堆原理到C++工程实践

堆(Heap)作为一种基于完全二叉树的高效数据结构,在计算机科学中广泛应用于优先队列、调度算法和Top K问题等场景。其核心原理是通过数组实现隐式二叉堆,利用父节点与子节点索引间的固定数学关系(父节点索引(i-1)/2,左子节点2*i+1,右子节点2*i+2)来维护堆序性质,无需显式指针连接,从而获得优异的空间局部性和缓存友好性。在C++标准模板库(STL)中,堆算法(如std::make_heap、std::push_heap、std::pop_heap)将数据结构与算法解耦,提供了比std::prior

dgoh41514的博客 400

在 AS ABAP 7.40 SP05 里把 HANA 存储过程纳入 ABAP 生命周期:AMDP 实战示例与踩坑笔记

文章摘要:AMDP(ABAP Managed Database Procedures)是SAP推出的框架,用于在ABAP中管理数据库端的存储过程或函数,特别适用于HANA数据库。它通过将数据库语言(如SQLScript)嵌入ABAP方法,实现数据处理逻辑的"下推"(code pushdown),减少应用层与数据库间的数据传输。AMDP适用于需要数据库特有能力或大规模数据处理的场景,但应优先考虑Open SQL或ABAP CDS等更简单的方案。开发时需注意数据库类型检查、参数前缀(:)等语

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 225

搜狗2017校招C++笔试试卷深度解析:考点、陷阱与备考指南

C++基础功底涵盖内存管理、STL容器与多态机制,是校招笔试中反复出现的核心考察点。理解虚函数表、智能指针引用计数以及vector扩容原理,能有效规避迭代器失效与内存泄漏等工程陷阱。以搜狗2017校招C++笔试试卷为切入点,深入剖析这些考点背后的设计逻辑、常见错误思路,并给出针对性备考策略与实践建议。

weixin_33894640的博客 396

YOLO模型轻量化实战:剪枝、量化与知识蒸馏三大技术落地详解

这篇文章结合我自己的实战经验,从原理、操作、效果、避坑四个方面,给大家讲清楚了YOLO模型轻量化的三大核心技术:剪枝、量化、知识蒸馏。先明确应用场景,再选择合适的技术组合,不要盲目追求极致压缩,要在“大小、速度、精度”之间找平衡。实战才是最好的学习方式——大家可以先拿自己的数据集试试剪枝和量化,感受一下效果,有问题可以在评论区留言。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 594

MIKE水动力笔记17_MIKE文件转shp、统计每个单元格的面积

MIKE的工具箱中自带一个转shp的工具,然后可以拖进ArcGIS中很方便的统计每个单元格的面积和每个网格点的水深。

晏长街的博客 4153

C/C++头文件机制详解:从声明定义分离到编译链接优化

在C/C++编程中,头文件是实现模块化编程和代码复用的核心机制。其本质是声明与定义的分离:头文件存放函数、类、变量的声明,作为接口说明书;源文件存放具体实现定义。这一设计遵循了C/C++的编译链接模型,每个源文件作为独立编译单元被处理,编译器只需声明信息进行语法检查,链接器再将各单元的定义合并。这种分离机制的价值在于提升代码的模块化、可维护性和编译效率。在实际工程中,头文件管理直接影响项目的健壮性,涉及包含守卫防止重复包含、前向声明减少依赖、合理使用内联与模板等关键实践。本文聚焦头文件的核心机制与常见陷阱,

weixin_33747129的博客 1468

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

C++模板进阶:非类型参数、特化与分离编译实战解析

泛型编程是C++实现代码复用与类型安全的核心机制,其原理在于通过模板在编译期生成针对特定类型的代码,从而提升程序的灵活性与性能。这一技术为构建高性能、可复用的基础库(如STL)提供了关键支持,广泛应用于容器、算法和元编程等场景。在工程实践中,开发者常需处理模板的进阶特性以满足复杂需求,例如使用非类型模板参数实现编译期常量优化,或通过模板特化为特定类型定制高效实现。本文聚焦于C++模板进阶中的核心挑战与解决方案,深入探讨非类型模板参数如何将值嵌入类型系统,以及模板特化如何实现类型定制,并针对常见的分离编译问题

weixin_33894640的博客 315

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

C++模板编程:从泛型基础到元编程实战

泛型编程是现代软件开发中实现代码复用的核心技术,它允许开发者编写与具体数据类型无关的通用算法和数据结构。其核心原理是通过参数化类型,在编译期生成针对特定类型的特化代码,从而实现类型安全的多态性。这一技术价值在于显著提升代码的复用率、减少冗余,并支持编译期计算与优化。在应用场景上,泛型编程广泛用于构建标准模板库(STL)中的容器(如vector、map)和算法,以及实现智能指针、元编程等高级特性。本文聚焦于C++模板机制,深入解析函数模板与类模板的实现,并探讨可变参数模板、模板特化等进阶主题,帮助开发者掌握这

weixin_34293059的博客 386

C++模板与泛型编程:从基础语法到实战应用全解析

泛型编程是一种将算法从特定数据类型中抽象出来的编程范式,其核心目标是提高代码的复用性。在C++中,这一范式主要通过模板技术实现,它允许开发者编写独立于数据类型的通用代码。模板的工作原理是在编译期间根据实际使用的类型自动生成类型安全的特化代码,实现了零运行时开销的编译期多态。这种技术价值在于它能大幅减少代码重复,提升开发效率,同时保持与手写特化代码相当的性能。在工程实践中,模板广泛应用于构建通用容器(如vector、map)、算法库以及资源管理工具(如智能指针)。通过函数模板处理通用算法,类模板设计数据结构,

weixin_30633405的博客 320

C++ Lambda表达式:从匿名函数到编译器生成的闭包类

在C++编程中,函数对象(Functor)是一种重载了operator()的类,用于实现可调用行为。其原理是通过类封装状态和行为,提供比普通函数更灵活的功能。这一机制的技术价值在于支持状态保持和泛型编程,广泛应用于标准库算法和回调场景。随着C++11标准的引入,Lambda表达式作为语法糖出现,它本质上会在编译期自动生成一个唯一的匿名类类型(闭包类型),极大地简化了函数对象的定义。Lambda通过捕获列表实现闭包,支持按值和按引用捕获外部变量,同时借助mutable关键字控制内部状态的可变性。在性能方面,由

weixin_30407613的博客 429
上一篇: 现代C++实践100练:为什么使用nullptr代替NULL?因为它更加风骚
下一篇: 现代c++实践:变量声明强化,竟然可以在if/switch中定义变量!
CodeBowl
博客等级 码龄5年 7664粉丝 67原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值