C/C++语言基础--C++模板与元编程系列三(变量模板、constexpr、萃取等…………)

本专栏目的

  • 更新C/C++的基础语法,包括C++的一些新特性

前言

  • 模板与元编程是C++的重要特点,也是难点,本人预计将会更新10期左右进行讲解,这是第三期,讲变量模板、constexpr、萃取等知识
  • C语言后面也会继续更新知识点,如内联汇编;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

    • 非类型模板参数
    • 别名模板
    • 变量模板(C++14)
      • 定义格式
      • cosntexpr
        • constexpr定义的一定是常量
        • constexpr与函数
        • constexpr修饰接收函数返回值变量
      • 变量模板的使用
        • 非静态变量
        • 类静态变量
      • 在C++14之前没有变量模板之前
    • 类型萃取(简单了解)
      • is_pod

前言
上两次笔记咱们已经学习了C/C++语言基础–C++模板与元编程系列一(泛型、模板、函数模板、全特化函数模板………)和C/C++语言基础–C++模板与元编程系列二类模板、全特化、偏特化、编译模型简介、实现简单Vetctor等…………),加下来学习另外两个模板。

  • 别名模板(C++11):
  • 变量模板(C++14):

非类型模板参数

📘 准备

模板参数并不局限于定义类型,可以使用编译器内置类型作为参数,在编译期间变成模板的特定常量,这也是元编程的思想之一,C++元编程中核心思想之一就是在编译的时候确定类型,从而对不同类型进行不同计算

非类型模板参数:就是说在template定义模板类型的时候,可以定义编译器内置类型,这样就不是定义模板类型参数了。

👓 示例:

编写一个封装了静态数组的类,类名为Array

#include <iostream>// 简单版本,不扩容
template<typename T, size_t _size=10>
class Array
{
public:void push_back(T data){_array[_index++] = data;}T& operator[](size_t index){return _array[index];}size_t size()const{return _index;}private:T _array[_size]{};size_t _index{};
};int main()
{Array<int> array;for (int i = 1; i <= 10; i++) {array.push_back(i);}for (int i = 0; i < array.size(); i++) {std::cout << array[i] << " ";}/*输出:1 2 3 4 5 6 7 8 9 10*/return 0;
}

☀️ 在案例中

  • 我们定义了一个模板类型参数T,同时也定义了一个非模板类型参数size_t类型,并且赋值为10;
  • 定义的非模板类型参数也是一样可以在类中使用,有点像函数的默认参数。

别名模板

我们在写程序的过程中,总是希望写简短的代码,给一些复杂的名称简化,或者取一个简短的名字,于是又有了类型别名,用来重新定义复杂的名字

🐤 C的typedef

使用typedef不仅可以对遍历取别名,还可以为模板具体化指定别名,🍡 🍡🍡 ​, 注意:是模板具体化

//模板别名
//1,typedef
typedef Array<int, 20> IntArr;

注意: 不能为模板类取别名。

// 如:
template <typename T>
typedef Array<T, 20> _Array;

报错:

在这里插入图片描述

解决方法:C++新特性using

⛅️ C++新特性using

typdef定义不了别名模板,所以C++11新增了一项功能——使用模板提供一系列别名(模板别名),当然也同样可以对编译器类型取别名。

🔛 模板具体类取别名

//2,using
using _IntArr = Array<int, 20>;  // 语法

🎊 模板类取别名

template <typename T>
using _Array = Array<T, 20>;

这样定义好之后,使用_Array就相当于使用Array<T,20>

变量模板(C++14)

概念:变量模板(Variable Templates)是 C++14 引入的一个新特性,它允许你定义一个模板,该模板在实例化时会生成一个具有特定类型的变量。变量模板的主要作用是减少代码冗余,提高代码的灵活性和可维护性。

概括

  • 模板实例化生成具体类型变量
  • 减少代码冗余

定义格式

template<typename T>
T name = value;
  • name:变量名
  • value:初始值

cosntexpr

变量模板一般会结合constexpr使用,constexprconst的升级优化版,最大区别是const定义的不一定是常量,但是constexpr一定是常量,这个什么意思呢??

如下代码:

int sum = 10;
const int csum = sum;

这里,将sum值赋值给const变量csum,但是csum是一个变量,不是常量啊,他在程序运行的时候才会是常量。


constexpr定义的一定是常量

C++针对以上情况,提出了cosntexpr这个关键字,这个关键字定义的变量是在编译的时候计算出来的,一定是常量,不可能是变量,如下代码:

int sum = 10;
constexpr int csum = sum;

报错error C2131: 表达式的计算结果不是常数


constexpr与函数

由于constexpr 是在编译的时候检查的,所以把函数声明为constexpr 了,这样编译器就会大胆优化,只要是出现CharMax()的地方,直接用127替代,是不是和宏很类似?确实,但是宏没有运行时安全检查,这也是为什么有些大佬提议用C++重写Linux内核的原因之一。

注意 : constexpr声明的函数,函数体不要写的太复杂(以前只允许一行代码)

如下:

constexpr uint8_t CharMax()
{int max = 117;for (int i = 0; i < 10; i++){++max;}return max;
}

这个时候,调用constexpr 返回的就是127,常量的127


constexpr修饰接收函数返回值变量

废话不多说,直接上代码:

size_t getNum()
{return 127;
}
// 调用
constexpr size_t num = getNum();// 报错:表达式必须含有常量值无法调用非 constexpr 函数"getNum"(已声明 所在行数:31)

☀️ 总结

  • 如果用constexpr修饰接收函数返回值变量,那么这个函数返回值夜泊徐要用constexpr修饰。

  • 解决方法如下:

  • constexpr size_t getNum()
    {return 127;
    }
    

变量模板的使用

非静态变量
  • 从变量模板实例化的变量被称为**被实例化变量,从静态数据成员模板实例化的变量被称为被实例化静态数据成员。**

  • 一般结合constexpr使用,如下代码:

template<typename T>
constexpr T PI = T(3.14159265358L);template<typename T>
T circle_area(T r)
{return PI<T> *r * r;	//PI<是变量模板实例化>
}

首先声明了一个变量模板PI,在后面就可以使用各种类型的PI了(如:PI、PI、PI等等),非常方便,简化了代码。


类静态变量

在类作用域中使用时,变量模板声明一个静态数据成员模板。与其他静态成员一样,静态数据成员模板的需要一个定义。这种定义可以在类定义外提供:

  • 静态数据,成员模板,静态成员没有加const需要在类外中初始化
struct Limits
{template<typename T>   // 静态数据的 成员变量模板static T max;
};
template<typename T>
const T Limits::max = {};  //注意 注意 注意,这时不需要加static
  • 类模板的非静态数据成员
template<typename T>
struct Foo
{static const T foo;
};
template<typename T>
const T Foo<T>::foo =   //是类模板,一定要与“静态成员,成员模板”做好区分,是在哪里进行显示转换

其实如果静态变量声明的是const,并且有初始值,那么可以不用在内外定义,会自动内联。(注意此时不能在外面声明);

class Test
{
public:static const int count = 0;          
};
cout << Test::count << endl;	//可以直接使用

在C++14之前没有变量模板之前

在 C++14 引入变量模板前,参数化变量通常实现为类模板的静态数据成员,或返回所需值的 constexpr 函数模板

#include <iostream>using namespace std;//1,使用变量模板
template<typename T>
constexpr T PI = T(3.14159265358);//2,使用函数模板
template<typename T>
constexpr T getPI()
{return T(3.14159265358);
}//3,使用类模板
template<typename T>
struct Math
{static constexpr T PI = T(3.14159265358);
};int main()
{cout << PI<int> << " " << PI<float> << endl;cout << getPI<int>() << " " << getPI<float>() << endl;cout << Math<int>::PI << " " << Math<float>::PI << endl;/*3 3.141593 3.141593 3.14159*/return 0;
}

类型萃取(简单了解)

类型萃取,可简单理解为类型获取。对不同类型对象进行不同处理,可以提升程序效率,要注意的是:是在编译的时候确定类型,这也是元编程的核心思想之一,在编译的时候去区分、确定类型,然后针对不同类型做不同处理。

is_pod

萃取的典型应用是在模板函数中区分T的类型是原生类型POD还是自定义类型,POD全称plain old data,简单理解就是C++从C继承来的基本数据类型,如int、double等

之所以需要区分类型,主要是因为POD类型与自定义类型的很多处理方法不同,典型的就是copy,POD可以直接使用C库提供的memcpy,它主要是实现内存层面的拷贝,而非POD类型需要使用for循环挨个拷贝,因为涉及到深拷贝与浅拷贝的问题,所以在模板中需要识别数据类型,再做不同处理。

如以下代码,用来判断int类型是不是POD类型,有三种使用方式:

cout << std::boolalpha << is_pod<int>::value << endl;	//获取静态成员
cout << std::boolalpha << is_pod<int>() << endl;		//类型转换函数
cout << std::boolalpha << is_pod<int>()() << endl;		//operaotr()函数

输出结果

true
true
true

说明int确实是POD类型。

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

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

相关文章

基于微信小程序的移动学习平台的设计与实现+ssm(lw+演示+源码+运行)

摘 要 由于APP软件在开发以及运营上面所需成本较高&#xff0c;而用户手机需要安装各种APP软件&#xff0c;因此占用用户过多的手机存储空间&#xff0c;导致用户手机运行缓慢&#xff0c;体验度比较差&#xff0c;进而导致用户会卸载非必要的APP&#xff0c;倒逼管理者必须改…

RAG 系统的分块难题:小型语言模型如何找到最佳断点?

之前我们聊过 RAG 里文档分块 (Chunking) 的挑战&#xff0c;也介绍了 迟分 (Late Chunking) 的概念&#xff0c;它可以在向量化的时候减少上下文信息的丢失。今天&#xff0c;我们来聊聊另一个难题&#xff1a;如何找到最佳的分块断点。 虽然迟分对边界位置不敏感&#xff0c;…

服务器作业2

关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 配置文件 创建用户nfs-upload [rootlocalhost ~]# useradd -u 210 nfs-upload [rootlocalhost ~]# groupmod -g 210 nfs-upload 创建tom用户 [rootlocalhost ~]# useradd tom 查看to…

Java爱情交友婚恋系统小程序源码

&#x1f491;【恋爱攻略】交友婚恋系统&#xff0c;遇见对的TA不再难&#xff01;&#x1f496;&#x1f4ab; &#x1f48c; 开篇&#xff1a;数字时代&#xff0c;寻觅真爱的新方式 在这个快节奏的数字时代&#xff0c;寻找真爱似乎成了一件既期待又头疼的事情。&#x1f…

飞牛fnOs内网穿透-使用Lucky实现ipv6动态解析+HTTPS访问NAS服务

&#x1f9ed;Lucky官方介绍 Lucky最初是作为一个小工具&#xff0c;由开发者为自己的个人使用而开发&#xff0c;用于替代socat&#xff0c;在小米路由AX6000官方系统上实现公网IPv6转内网IPv4的功能。Lucky的设计始终致力于让更多的Linux嵌入式设备运行&#xff0c;以实现或…

Java外卖霸王餐CPS优惠CPS平台自主发布小程序系统源码

外卖霸王餐CPS平台系统&#x1f37d;️&#xff1a;省钱吃大餐的新神器 &#x1f389; 引言&#xff1a;霸王餐不再是梦 在这个快节奏的生活中&#xff0c;外卖已经成为了我们日常饮食的重要组成部分。然而&#xff0c;每次点外卖都要精打细算&#xff0c;是否让你感到疲惫&a…

Java项目实战II基于Spring Boot的智慧生活商城系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着科技的飞速发展&#xff0c;人们的…

qt QFile详解

1、概述 QFile类是Qt框架中用于读取和写入文本和二进制文件资源的I/O工具类。它继承自QFileDevice类&#xff0c;后者又继承自QIODevice类。QFile类提供了一个接口&#xff0c;允许开发者以二进制模式或文本模式对文件进行读写操作。默认情况下&#xff0c;QFile假定文件内容为…

电脑软件:推荐一款免费且实用的电脑开关机小工具

目录 一、软件简介 二、软件功能 三、软件特点 四、使用说明 五、软件下载 今天给大家推荐一款免费且实用的电脑开关机小工具KShutdown&#xff0c;有需要的朋友可以下载试一下&#xff01; 一、软件简介 KShutdown是一款精巧且实用的定时自动关机小工具&#xff0c;对于…

初阶数据结构【TOP】- 16. 经典八大排序对比

文章目录 前言一、相关复杂度二、相关稳定性三、表格总结总结 前言 本篇文章笔者将会对排序算法的所有时间复杂度和稳定性进行分析. 一、相关复杂度 ● 简单选择排序 首先,选择排序的效率是不高的 , 时间复杂度考虑的是最坏情况 , 那么对于选择排序来说, 最坏情况下需要进行…

Postman断言与依赖接口测试详解!

在接口测试中&#xff0c;断言是不可或缺的一环。它不仅能够自动判断业务逻辑的正确性&#xff0c;还能确保接口的实际功能实现符合预期。Postman作为一款强大的接口测试工具&#xff0c;不仅支持发送HTTP请求和接收响应&#xff0c;还提供了丰富的断言功能&#xff0c;帮助测试…

基于 JAVASSM(Java + Spring + Spring MVC + MyBatis)框架开发一个九宫格日志系统

基于 JAVASSM&#xff08;Java Spring Spring MVC MyBatis&#xff09;框架开发一个九宫格日志系统 步骤一&#xff1a;需求分析 明确系统需要实现的功能&#xff0c;比如&#xff1a; 用户注册和登录添加日志&#xff08;包含标题、内容、图片&#xff09;查看日志列表…

003-Kotlin界面开发之声明式编程范式

概念本源 在界面程序开发中&#xff0c;有两个非常典型的编程范式&#xff1a;命令式编程和声明式编程。命令式编程是指通过编写一系列命令来描述程序的运行逻辑&#xff0c;而声明式编程则是通过编写一系列声明来描述程序的状态。在命令式编程中&#xff0c;程序员需要关心程…

华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)

华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目分享——共九套&#xff08;每套四十题&#xff09; 岗位——芯片与器件设计工程师 岗位意向——模拟芯片 真题题目分享&#xff0c;完整题目&#xff0c;无答案&#xff08;共8套&#xff09; 实习岗位…

解决程序因缺少xinput1_3.dll无法运行的有效方法,有效修复丢失xinput1_3.dll

如果你的电脑在运行某些应用程序或游戏时提示“xinput1_3.dll丢失”或“找不到xinput1_3.dll”的错误消息&#xff0c;那么很可能是因为你的系统中缺少这个重要的DLL文件而导致的问题。那么电脑出现xinput1_3.dll丢失的问题时有哪些方法进行修复呢&#xff1f; 如何确定电脑是否…

入门网络安全工程师要学习哪些内容

&#x1f91f; 基于入门网络安全/黑客打造的&#xff1a;&#x1f449;黑客&网络安全入门&进阶学习资源包 大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网…

命令行参数、环境变量、地址空间

命令行参数&#xff1a; int main(int argc, char *argv[ ])&#xff0c;main的参数可带可不带。argc参数通常代表后面的char *argv的元素个数有多少。 在linux中会把输入的字符串存到char *argv[ ]中&#xff0c;在数组的结尾为NULL。 命令行参数可以让同一个程序可以通过不同…

Docker学习—Docker核心概念总结

核心概念总结 容器&#xff1a;容器就是将应用运行所需的所有内容比如代码、运行时环境&#xff0c;进行打包和隔离。 容器和虚拟机的对比 虚拟机是在同一个硬件上虚拟化出多个操作系统&#xff08;OS&#xff09;实例。 容器是在操作系统上进行虚拟化&#xff0c;用于隔离…

Java实战项目-基于SpringBoot的新能源汽车个性化推荐系统

博主介绍&#xff1a;✌Java徐师兄、7年大厂程序员经历。全网粉丝13w、csdn博客专家、掘金/华为云等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不…

统信UOS设备驱动开发-常见问题

包含linux设备驱动开发的基础知识及统信UOS设备驱动的总体架构,常用的设备驱动开发调试优化手段及在环境搭建和代码编写过程中常见问题处理等。 文章目录 环境搭建如何编译驱动代码编写如何实现同源异构环境搭建 如何编译内核 下载并解压内核源码包,进入源码根目录,内核的编…