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. if 和 switch 语句中的初始化(If and Switch with Initialization)
C++17 允许在 if 和 switch 语句中直接进行初始化,增强了代码的简洁性。
#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 - 模板介绍
目录 一:C11 之前的模板特性 1. 函数模板: 2. 类模板: 3. 模板特化: 4. 模板参数: 5. 模板元编程: 二:C11的模板特性 1. 变长模板(Variadic Templates)ÿ…...
算法笔记(七)——哈希表
文章目录 两数之和判定是否互为字符重排存在重复元素存在重复元素 II字母异位词分组 哈希表:一种存储数据的容器; 可以快速查找某个元素,时间复杂度O(1); 当频繁查找某一个数时,我们可以使用哈希表 创建一个容器&#…...
【基础算法总结】链表篇
目录 一, 链表常用技巧和操作总结二,算法原理和代码实现2.两数相加24.两两交换链表中的节点143.重排链表23.合并k个升序链表25.k个一组翻转链表 三,算法总结 一, 链表常用技巧和操作总结 有关链表的算法题也是一类常见并且经典的题…...
探索路由器静态IP的获取方式
在网络配置中,路由器静态IP是一个重要的概念。对于家庭网络或办公室网络而言,正确配置静态IP地址是确保网络稳定性和管理的关键步骤之一。但是,很多人对于静态IP地址的获取方式可能感到困惑。在本文中,我们将探讨它的获取途径&…...
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(JSON Web Token)是一种开放标准(RFC 7519)&#…...
CSS3练习--电商web
免责声明:本文仅做分享! 目录 小练--小兔鲜儿 目录构建 SEO 三大标签 Favicon 图标 布局网页 版心 快捷导航(shortcut) 头部(header) logo 导航 搜索 购物车 底部(footer࿰…...
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.他们是什么 (1…...
深入理解JavaScript 的原型继承
JavaScript 的原型链继承机制和 Java 的类继承机制有明显的区别,虽然它们都用于实现对象之间的继承,但它们的实现方式、概念以及运行机制都不同。 1. JavaScript 的原型继承 JavaScript 是基于原型链的继承,主要依赖对象的 __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 开发人员套件 (PCDK) 从 PC 命令和配置机器人的简单方法。该套件允许 PC 访问机器人上的变量、寄存器、IO、程序、位置和警报;接下来,我将如何开始使用 C#。 连接到机器人 将以下突出显示的行添加…...
如何在wsl中使用beyond compare
寫一個名為bc4的文件,內容如下: #!/bin/sh /mnt/c/Program\ Files/Beyond\ Compare\ 4/BComp.com $(wslpath -aw $1) $(wslpath -aw $2)bc4 file1 file2參考:https://forum.scootersoftware.com/forum/beyond-compare-4-discussion/version-…...
CNN+Transformer在自然语言处理中的具体应用
在自然语言处理(NLP)领域,CNN(卷积神经网络)和Transformer架构各自有着广泛的应用。NLP中的具体应用: CNN在NLP中的应用 1.文本分类:CNN可以用于文本分类任务,如情感分析、垃圾邮件…...
DotNetty ChannelRead接收数据为null
问题:C#使用Dotnetty和Java netty服务器通讯,结果能正确发送数据到服务器,却始终接收不到服务器返回的数据。 解决:一定一定要注意服务器和客户端使用的编码一定要完全一样才行 我先前在客户端添加了StringDecoder,服务器却没有…...
3分钟学会下载 blender
1. blender简介 Blender是一款开源的3D创作套件,它由Blender Foundation维护,并得到了全球志愿者和专业开发者的支持。Blender广泛应用于3D模型的制作、动画、渲染、视频编辑、游戏创建、模拟、 composting以及3D打印等多个领域。 功能特点:…...
实现Xshell与虚拟机中Linux服务器的连接(附常见错误解决)
前言 Xshell是一个强大的安全终端模拟软件,它支持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 系列芯片(如 ESP32、ESP32-S2、ESP32-C3 等࿰…...
项目-坦克大战笔记-墙体销毁以及人机销毁
在子弹撞到墙或者人机身上时会将碰撞到的墙体或者人机销毁 我们需要做到几点 检测子弹碰撞到的墙体或者人机将物体获取到 每帧遍历墙体列表与人机列表,检测被碰撞的墙,创建一个方法返回值为对应类型将被碰撞的物体返回出来 public static gudin wallp…...
硬件设计-利用环路设计优化PLL的输出性能
目录 前言 问题描述 问题分析步骤 杂散源头排查 245.76M 参考相噪: 30.72M VCXO的相噪性能测试如下: 解决方案 前言 LMK04832是TI 新发布的低抖动双环去抖模拟时钟, 其最高输出频率可以到达3250MHz, 输出抖动极低,3200MHz…...
避坑指南:glmnet做lasso回归时分类变量的3个常见错误及解决方法
避坑指南:glmnet做lasso回归时分类变量的3个常见错误及解决方法 在生物信息学和临床数据分析领域,lasso回归因其出色的变量选择能力而广受欢迎。R语言中的glmnet包是实现lasso回归的利器,但许多初学者在处理分类变量时频频踩坑。本文将揭示三…...
理论框架总搭不起来?资深导师力荐这几个AI写作辅助平台
写论文时,理论框架总是理不顺、逻辑不清晰?很多同学都遇到过这样的问题。其实,关键在于用对工具、走对流程——资深教授普遍建议,结合AI写作辅助平台能大幅提升效率。我们实测发现,千笔AI(中文全流程首选&a…...
Windows下OpenClaw部署教程:对接GLM-4.7-Flash模型详解
Windows下OpenClaw部署教程:对接GLM-4.7-Flash模型详解 1. 为什么选择OpenClawGLM-4本地组合 去年我在处理日常办公自动化时,发现很多重复性工作既不适合用Python脚本硬编码,又不想把敏感数据传到第三方SaaS平台。直到遇到OpenClaw这个开源…...
松江少儿英语口碑好的?
松江少儿英语口碑好的 环球乐学少儿英语,指出幼儿英语学习三大痛点: 1. 兴趣不足易抵触:教学形式枯燥,多以机械记单词、跟读为主,不符合幼儿认知特点,易产生厌学情绪。 2. 缺语境不会运用:…...
BilibiliDown终极指南:简单快速下载B站视频的完整教程
BilibiliDown终极指南:简单快速下载B站视频的完整教程 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/b…...
QGIS插件开发实战:手把手教你用Python调用高德地图API做路径规划(附坐标转换避坑指南)
QGIS插件开发实战:Python集成高德地图API的路径规划全流程解析 当我们需要在QGIS中实现路径规划功能时,高德地图API提供了丰富的服务接口。本文将带你从零开始,开发一个能够调用高德地图API进行路径规划的QGIS插件,并重点解决开发…...
对公司在使用AI变成的思考,我们是牧羊人吗?
当人类成为AI的牧羊人:在数字羊群中找回人的坐标晨光透过百叶窗,落在张工的键盘上。他刚刚用AI生成了三套前端方案,此刻正像牧羊人清点羊群般滑动鼠标核验代码。隔壁工位的李姐对着AI绘制的数据可视化图表皱眉——那根异常波动曲线像迷途的羔…...
高效智能歌词提取工具:跨平台音乐歌词获取解决方案
高效智能歌词提取工具:跨平台音乐歌词获取解决方案 【免费下载链接】163MusicLyrics Windows 云音乐歌词获取【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 在数字音乐时代,我们常常遇到想要学唱一首外语…...
WeChatExporter终极指南:如何完整备份微信聊天记录并永久保存珍贵回忆
WeChatExporter终极指南:如何完整备份微信聊天记录并永久保存珍贵回忆 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 微信聊天记录导出工具WeChatExporter是…...
嘎嘎降AI使用教程:手把手教你用嘎嘎降AI降论文ai率,从97%降到7%实操
嘎嘎降AI使用教程:手把手教你用嘎嘎降AI降论文ai率,从97%降到7%实操 说实话,我当时论文被检测出AI率97%的时候,整个人是懵的。导师直接把报告甩给我说"你这论文是不是全让AI写的",我那叫一个尴尬。后来折腾了…...
