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

C++ 语言特性30 - 模板介绍

目录

一:C++11 之前的模板特性

1. 函数模板:

2. 类模板:

3. 模板特化:

4. 模板参数:

5. 模板元编程:

二:C++11的模板特性 

1. 变长模板(Variadic Templates):

2. 右值引用和完美转发:

3. 类型别名模板(Type Alias Templates):

4.  decltype 关键字

5. 默认模板参数

6. 非类型模板参数

7. 模板特化

三:C++17的模板特性

1. 模板参数推导(Template Parameter Deduction for Class Templates)

2. std::optional

3. std::variant

4. if 和 switch 语句中的初始化(If and Switch with Initialization)

5. constexpr 增强

6. std::any

7.模板的 std::decay

四:C++20的模板特性

1. 概念(Concepts)

2. 模板参数的约束(Template Parameter Constraints)

3. 模板模板参数(Template Template Parameters):

 


一:C++11 之前的模板特性

  1. 函数模板

   允许定义可以接受不同类型参数的函数。函数模板在调用时根据参数类型进行实例化。

template<typename T>
T add(T a, T b) {return a + b;
}int main() {int result1 = add(3, 4);         // 实例化为 intdouble result2 = add(3.5, 2.5);  // 实例化为 double
}

 2. 类模板

  允许定义可以接受不同类型参数的类。类模板在创建对象时根据类型参数进行实例化。

template<typename T>
class Box {
public:Box(T value) : value(value) {}T getValue() { return value; }
private:T value;
};int main() {Box<int> intBox(10);      // 实例化为 Box<int>Box<std::string> strBox("Hello"); // 实例化为 Box<std::string>
}

3. 模板特化

 允许为特定类型提供不同的实现,称为模板特化。可以是完全特化或偏特化。

template<typename T>
class Box {
public:void print() { std::cout << "Generic Box" << std::endl; }
};// 完全特化
template<>
class Box<int> {
public:void print() { std::cout << "Integer Box" << std::endl; }
};int main() {Box<double> box1;box1.print(); // 输出 "Generic Box"Box<int> box2;box2.print(); // 输出 "Integer Box"
}

4. 模板参数

模板可以使用非类型参数,例如整数常量。

template<int size>
class Array {
public:int data[size]; // 使用非类型模板参数
};int main() {Array<10> arr; // 创建一个大小为 10 的数组
}

 5. 模板元编程

  在 C++11 之前,模板还可以用于编写编译时计算的元编程,例如计算阶乘、斐波那契数列等。

template<int N>
struct Factorial {static const int value = N * Factorial<N - 1>::value;
};template<>
struct Factorial<0> {static const int value = 1;
};int main() {int result = Factorial<5>::value; // result 为 120
}

二:C++11的模板特性 

1. 变长模板(Variadic Templates)

允许定义接受可变数量参数的模板,简化了如容器、函数等的模板定义。

#include <iostream>// 基础模板
template<typename T>
void print(T value) {std::cout << value << std::endl;
}// 变长模板
template<typename T, typename... Args>
void print(T first, Args... args) {std::cout << first << ", ";print(args...); // 递归调用
}int main() {print(1, 2.5, "Hello", 'A'); // 输出: 1, 2.5, Hello, A
}

 2. 右值引用和完美转发

引入了右值引用和 std::forward,使得模板能够更高效地处理不同类型的参数。

#include <iostream>
#include <utility>template<typename T>
void process(T&& arg) {// 处理 argstd::cout << arg << std::endl;
}template<typename T>
void wrapper(T&& arg) {process(std::forward<T>(arg)); // 完美转发
}int main() {int x = 10;wrapper(x); // 左值wrapper(20); // 右值
}

3. 类型别名模板(Type Alias Templates)

使用 using 定义类型别名模板,使得模板的可读性更强。

#include <iostream>
#include <vector>// 定义类型别名模板
template<typename T>
using Vec = std::vector<T>;int main() {Vec<int> intVec; // 实际上是 std::vector<int>intVec.push_back(1);std::cout << intVec[0] << std::endl; // 输出: 1
}

4.  decltype 关键字

decltype 关键字可以用于模板中,以便在编译时推导表达式的类型。

#include <iostream>template<typename T>
void displayType(T arg) {// 使用 decltype 获取类型decltype(arg) var = arg;std::cout << "Type of var: " << typeid(var).name() << std::endl;
}int main() {displayType(10);          // 输出: Type of var: intdisplayType(3.14);       // 输出: Type of var: double
}

5. 默认模板参数

C++11 允许为模板参数指定默认值,这样在某些情况下可以简化调用。

#include <iostream>template<typename T, int size = 10>
class Array {
public:T data[size]; // 使用默认模板参数void printSize() {std::cout << "Array size: " << size << std::endl;}
};int main() {Array<int> arr; // 使用默认参数arr.printSize(); // 输出: Array size: 10Array<double, 20> arr2; // 指定大小arr2.printSize(); // 输出: Array size: 20
}

6. 非类型模板参数

C++11 引入了更多类型的非类型模板参数,例如可以使用指针和引用作为模板参数。

#include <iostream>template<int N>
class Array {
public:int data[N]; // 使用非类型模板参数void printSize() {std::cout << "Array size: " << N << std::endl;}
};int main() {Array<5> arr; // 创建大小为 5 的数组arr.printSize(); // 输出: Array size: 5
}

7. 模板特化

在 C++11 中,你可以使用完全特化和部分特化来处理特定类型的情况。

#include <iostream>// 基础模板
template<typename T>
class Box {
public:void display() { std::cout << "Generic Box" << std::endl; }
};// 完全特化
template<>
class Box<int> {
public:void display() { std::cout << "Integer Box" << std::endl; }
};int main() {Box<double> box1;box1.display(); // 输出: Generic BoxBox<int> box2;box2.display(); // 输出: Integer Box
}

三:C++17的模板特性

1. 模板参数推导(Template Parameter Deduction for Class Templates)

C++17 允许在类模板中通过构造函数自动推导类型参数,从而简化模板的使用。

#include <iostream>template<typename T>
class Wrapper {
public:Wrapper(T value) : value(value) {}T getValue() const { return value; }
private:T value;
};int main() {Wrapper w(42); // T 被推导为 intstd::cout << w.getValue() << std::endl; // 输出: 42Wrapper<double> w2(3.14); // 显式指定类型std::cout << w2.getValue() << std::endl; // 输出: 3.14
}

2. std::optional

C++17 引入了 std::optional,用于表示可能没有值的情况,结合模板使用时非常方便。

#include <iostream>
#include <optional>std::optional<int> findValue(bool exists) {if (exists) return 42;return std::nullopt; // 表示无值
}int main() {auto value = findValue(true);if (value) {std::cout << *value << std::endl; // 输出: 42} else {std::cout << "No value found" << std::endl;}auto noValue = findValue(false);if (!noValue) {std::cout << "No value found" << std::endl; // 输出: No value found}
}

3. std::variant

std::variant 是 C++17 引入的一个类型安全的联合体,允许多个类型的值共存。

#include <iostream>
#include <variant>std::variant<int, double, std::string> getValue(bool flag) {if (flag) return 10;return 3.14; // 返回 double
}int main() {auto value = getValue(true);// 使用 std::visit 处理 variantstd::visit([](auto&& arg) {std::cout << arg << std::endl; // 输出: 10}, value);value = getValue(false);std::visit([](auto&& arg) {std::cout << arg << std::endl; // 输出: 3.14}, value);
}

4. ifswitch 语句中的初始化(If and Switch with Initialization)

C++17 允许在 ifswitch 语句中直接进行初始化,增强了代码的简洁性。

#include <iostream>bool checkValue() {return true;
}int main() {// 在 if 语句中初始化if (auto value = checkValue()) {std::cout << "Value is true" << std::endl;} else {std::cout << "Value is false" << std::endl;}
}

5. constexpr 增强

C++17 扩展了 constexpr 的功能,使得模板可以在编译时进行更多计算。

#include <iostream>constexpr int factorial(int n) {return n <= 1 ? 1 : n * factorial(n - 1);
}int main() {constexpr int value = factorial(5); // 在编译时计算std::cout << "Factorial of 5: " << value << std::endl; // 输出: Factorial of 5: 120
}

6. std::any

std::any 是 C++17 引入的另一种类型安全的容器,允许存储任意类型的值。

#include <iostream>
#include <any>int main() {std::any anyValue = 10; // 存储整数std::cout << std::any_cast<int>(anyValue) << std::endl; // 输出: 10anyValue = std::string("Hello, World!"); // 存储字符串std::cout << std::any_cast<std::string>(anyValue) << std::endl; // 输出: Hello, World!
}

7.模板的 std::decay

C++17 引入了 std::decay,用于获取参数类型的“衰变”类型,常用于模板中。

#include <iostream>
#include <type_traits>template<typename T>
void printType(T&& arg) {using DecayedType = typename std::decay<T>::type;std::cout << "Type: " << typeid(DecayedType).name() << std::endl;
}int main() {int x = 10;printType(x); // 输出类型为 intprintType(20); // 输出类型为 intprintType("Hello"); // 输出类型为 const char*
}

四:C++20的模板特性

1. 概念(Concepts)

概念用于定义模板参数的约束条件,使得模板编程更加类型安全和可读。

#include <iostream>
#include <concepts>// 定义一个概念:必须是可加的类型
template<typename T>
concept Addable = requires(T a, T b) {{ a + b } -> std::same_as<T>;
};template<Addable T>
T add(T a, T b) {return a + b;
}int main() {std::cout << add(5, 10) << std::endl; // 输出: 15// std::cout << add(5.5, 2.5) << std::endl; // 正确,输出: 8.0// std::cout << add("Hello", "World"); // 错误,类型不满足 Addable 概念
}

2. 模板参数的约束(Template Parameter Constraints)

C++20 允许在模板定义中直接使用概念作为参数约束,增加了代码的可读性和类型安全。

#include <iostream>
#include <concepts>template<typename T>
void process(T value) requires std::integral<T> {std::cout << "Processing integral value: " << value << std::endl;
}int main() {process(10); // 正确// process(3.14); // 错误,double 不是整数
}

3. 模板模板参数(Template Template Parameters)

增强了对模板模板参数的支持,可以更灵活地处理各种模板结构。

template<template<typename> class Container, typename T>
void process(Container<T> c) {// 处理容器
}

相关文章:

C++ 语言特性30 - 模板介绍

目录 一&#xff1a;C11 之前的模板特性 1. 函数模板&#xff1a; 2. 类模板&#xff1a; 3. 模板特化&#xff1a; 4. 模板参数&#xff1a; 5. 模板元编程&#xff1a; 二&#xff1a;C11的模板特性 1. 变长模板&#xff08;Variadic Templates&#xff09;&#xff…...

算法笔记(七)——哈希表

文章目录 两数之和判定是否互为字符重排存在重复元素存在重复元素 II字母异位词分组 哈希表&#xff1a;一种存储数据的容器&#xff1b; 可以快速查找某个元素&#xff0c;时间复杂度O(1)&#xff1b; 当频繁查找某一个数时&#xff0c;我们可以使用哈希表 创建一个容器&#…...

【基础算法总结】链表篇

目录 一&#xff0c; 链表常用技巧和操作总结二&#xff0c;算法原理和代码实现2.两数相加24.两两交换链表中的节点143.重排链表23.合并k个升序链表25.k个一组翻转链表 三&#xff0c;算法总结 一&#xff0c; 链表常用技巧和操作总结 有关链表的算法题也是一类常见并且经典的题…...

探索路由器静态IP的获取方式

在网络配置中&#xff0c;路由器静态IP是一个重要的概念。对于家庭网络或办公室网络而言&#xff0c;正确配置静态IP地址是确保网络稳定性和管理的关键步骤之一。但是&#xff0c;很多人对于静态IP地址的获取方式可能感到困惑。在本文中&#xff0c;我们将探讨它的获取途径&…...

Vivado - JTAG to AXI Master (GPIO、IIC、HLS_IP)

目录 1. 简介 2. JTAG to AXI Master 2.1 添加 IP Core 2.2 基本TCL命令 2.2.1 复位 JTAG-to-AXI Master 2.2.2 创建并运行写入传输事务 2.2.3 创建并运行读取传输事务 2.2.4 命令列表 2.3 帮助信息 2.4 创建TCL读写程序 2.4.1 Read proc 2.4.2 Write proc 2.4.3 …...

Java中JWT(JSON Web Token)的运用

目录 1. JWT的结构2. JWT的优点3. JWT的流转过程4.具体案例一、项目结构二、依赖配置三、用户模型四、JWT工具类五、JWT请求过滤器六、安全配置七、身份验证控制器八、测试JWT JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#…...

CSS3练习--电商web

免责声明&#xff1a;本文仅做分享&#xff01; 目录 小练--小兔鲜儿 目录构建 SEO 三大标签 Favicon 图标 布局网页 版心 快捷导航&#xff08;shortcut&#xff09; 头部&#xff08;header&#xff09; logo 导航 搜索 购物车 底部&#xff08;footer&#xff0…...

Linux 默认内核版本更改

随笔记录 目录 1. 背景介绍 2. 解决方法 2.1 查看所有可用版本 2.2 安装指定版本内核 2.3 检查当前内核列表 2.4 检查当前默认内核 2.5 设置新的默认内核 2.6 确认内核是否成功加载 2.7 重启 2.8 删除其他版本内核 1. 背景介绍 linux 一般安装多个内核版本&…...

【ubuntu】修改用户名、主机名、主文件夹名、登录名、密码

目录 1.他们是什么 2.修改方法 2.1 修改用户密码 2.2 修改主机名 2.2.1 切换到root用户 2.2.2 修改名称 2.3 修改用户名 主文件夹名 登录名 2.2.1 sudoers 2.2.2 passwd 2.2.3 shadow 2.2.4 group 2.2.5 修改主文件夹名 3.重启 1.他们是什么 &#xff08;1&#xf…...

深入理解JavaScript 的原型继承

JavaScript 的原型链继承机制和 Java 的类继承机制有明显的区别&#xff0c;虽然它们都用于实现对象之间的继承&#xff0c;但它们的实现方式、概念以及运行机制都不同。 1. JavaScript 的原型继承 JavaScript 是基于原型链的继承&#xff0c;主要依赖对象的 __proto__ 属性或…...

Error while loading conda entry point: conda-libmamba-solver

问题 解决方法 conda install --solverclassic conda-forge::conda-libmamba-solver conda-forge::libmamba conda-forge::libmambapy conda-forge::libarchive...

FANUC机器人—PCDK

前言 FANUC提供了一种使用其 PC 开发人员套件 &#xff08;PCDK&#xff09; 从 PC 命令和配置机器人的简单方法。该套件允许 PC 访问机器人上的变量、寄存器、IO、程序、位置和警报&#xff1b;接下来&#xff0c;我将如何开始使用 C#。 连接到机器人 将以下突出显示的行添加…...

如何在wsl中使用beyond compare

寫一個名為bc4的文件&#xff0c;內容如下&#xff1a; #!/bin/sh /mnt/c/Program\ Files/Beyond\ Compare\ 4/BComp.com $(wslpath -aw $1) $(wslpath -aw $2)bc4 file1 file2參考&#xff1a;https://forum.scootersoftware.com/forum/beyond-compare-4-discussion/version-…...

CNN+Transformer在自然语言处理中的具体应用

在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;CNN&#xff08;卷积神经网络&#xff09;和Transformer架构各自有着广泛的应用。NLP中的具体应用&#xff1a; CNN在NLP中的应用 1.文本分类&#xff1a;CNN可以用于文本分类任务&#xff0c;如情感分析、垃圾邮件…...

DotNetty ChannelRead接收数据为null

问题&#xff1a;C#使用Dotnetty和Java netty服务器通讯&#xff0c;结果能正确发送数据到服务器&#xff0c;却始终接收不到服务器返回的数据。 解决&#xff1a;一定一定要注意服务器和客户端使用的编码一定要完全一样才行 我先前在客户端添加了StringDecoder,服务器却没有…...

3分钟学会下载 blender

1. blender简介 Blender是一款开源的3D创作套件&#xff0c;它由Blender Foundation维护&#xff0c;并得到了全球志愿者和专业开发者的支持。Blender广泛应用于3D模型的制作、动画、渲染、视频编辑、游戏创建、模拟、 composting以及3D打印等多个领域。 功能特点&#xff1a…...

实现Xshell与虚拟机中Linux服务器的连接(附常见错误解决)

前言 Xshell是一个强大的安全终端模拟软件&#xff0c;它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。 本文将介绍Xshell与虚拟机中Linux服务器连接…...

Rust 语言开发 ESP32C3 并在 Wokwi 电子模拟器上运行(esp-hal 非标准库、LCD1602、I2C)

文章目录 esp-rs 简介GithubRust 包仓库Rust 教程Wokwi 电子模拟器开发环境Rust 环境esp-rs 环境创建 ESP32C3 项目项目结构编译项目命令运行模拟器ESP32C3 烧录 esp-rs 简介 esp-rs 是一个专注于为 Espressif 系列芯片&#xff08;如 ESP32、ESP32-S2、ESP32-C3 等&#xff0…...

项目-坦克大战笔记-墙体销毁以及人机销毁

在子弹撞到墙或者人机身上时会将碰撞到的墙体或者人机销毁 我们需要做到几点 检测子弹碰撞到的墙体或者人机将物体获取到 每帧遍历墙体列表与人机列表&#xff0c;检测被碰撞的墙&#xff0c;创建一个方法返回值为对应类型将被碰撞的物体返回出来 public static gudin wallp…...

硬件设计-利用环路设计优化PLL的输出性能

目录 前言 问题描述 问题分析步骤 杂散源头排查 245.76M 参考相噪&#xff1a; 30.72M VCXO的相噪性能测试如下: 解决方案 前言 LMK04832是TI 新发布的低抖动双环去抖模拟时钟&#xff0c; 其最高输出频率可以到达3250MHz&#xff0c; 输出抖动极低&#xff0c;3200MHz…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

加密通信 + 行为分析:运营商行业安全防御体系重构

在数字经济蓬勃发展的时代&#xff0c;运营商作为信息通信网络的核心枢纽&#xff0c;承载着海量用户数据与关键业务传输&#xff0c;其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级&#xff0c;传统安全防护体系逐渐暴露出局限性&a…...