template<typename Func, typename = void> 在类模板中的应用
1、基础语法
在 C++ 中,template<typename Func, typename = void> 这一模板声明不仅仅限于函数模板,它在类模板中同样具有强大的应用。结合 SFINAE(Substitution Failure Is Not An Error)和 类型特征(type traits),我们可以根据类型特征(如是否可调用、是否为某种类型等)来实现不同的类特化,从而使得我们的代码更加灵活、可扩展。
在类模板中,template<typename Func, typename = void> 的基本结构类似于函数模板,但其作用是为类提供更强的类型约束和灵活性。例如:
template<typename Func, typename = void>
class MyClass {
public:void call(Func&& f) {// Generic behavior}
};
这里,template<typename Func, typename = void> 表示 MyClass 是一个模板类,它接受一个类型参数 Func,第二个模板参数 = void 是默认值。该类可以根据不同类型的 Func 做出不同的行为,而 = void 通常用于与 SFINAE 机制配合,决定是否允许某些特定的类型实例化该类模板。
2、类模板的默认类型参数:简化和泛化
与函数模板类似,template<typename Func, typename = void> 在类模板中的一个常见用途是通过默认类型参数简化模板声明。我们通常使用第二个类型参数 = void 来启用某些特化或重载,这通常结合 SFINAE 使用。通过这种方式,模板类在默认情况下为某些类型提供通用行为,而在遇到特定类型时可以提供特化的行为。假设我们希望在类模板 MyClass 中提供一个 call 成员函数,当 Func 是可调用类型时,执行该函数,而如果 Func 不是可调用类型,则提供默认行为,代码如下:
#include <iostream>
#include <type_traits>template<typename Func, typename = void>
class MyClass {
public:void call(Func&& f) {std::cout << "Generic version of call" << std::endl;}
};// 特化版本:当 Func 是可调用类型时
template<typename Func>
class MyClass<Func, typename std::enable_if<std::is_invocable<Func>::value>::type> {
public:void call(Func&& f) {std::cout << "Callable function version of call" << std::endl;f(); // 执行传入的可调用对象}
};void test_func() {std::cout << "test_func executed!" << std::endl;
}int main() {MyClass<int> obj1;obj1.call(42); // 输出: Generic version of callMyClass<void(*)()> obj2;obj2.call(test_func); // 输出: Callable function version of call// test_func executed!
}
- 通用版本:当 Func 不是可调用类型时,MyClass<Func, typename = void> 使用默认版本的 call 函数输出 “Generic version of call”。
- 特化版本:当 Func 是可调用类型时,我们通过 std::enable_if 和 std::is_invocable 来限制模板实例化,使得编译器选择特化版本的 call,在这种情况下,我们可以直接调用 f() 来执行传入的可调用对象。
3、SFINAE:类模板中根据类型特征选择特化
template<typename Func, typename = void> 还常常与 SFINAE 结合使用来根据类型的不同提供不同的实现。SFINAE 机制允许在类型不匹配时,编译器不报错,而是选择其他合适的模板特化或重载版本。可以使用该技术根据类型特征提供不同的成员函数,我们将使用 std::is_integral 和 std::is_floating_point 类型特征来为整数类型和浮动类型提供不同的处理方法:
#include <iostream>
#include <type_traits>template<typename T, typename = void>
class MyClass {
public:void print() {std::cout << "Generic version: Unknown type" << std::endl;}
};// 特化版本:当 T 是整数类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:void print() {std::cout << "Integer version: " << sizeof(T) << " bytes" << std::endl;}
};// 特化版本:当 T 是浮动类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:void print() {std::cout << "Floating point version: " << sizeof(T) << " bytes" << std::endl;}
};int main() {MyClass<int> obj1;obj1.print(); // 输出: Integer version: 4 bytesMyClass<double> obj2;obj2.print(); // 输出: Floating point version: 8 bytesMyClass<std::string> obj3;obj3.print(); // 输出: Generic version: Unknown type
}
- 通用版本:对于非整数和非浮动类型,MyClass 使用通用版本的 print 成员函数。
- 整数类型特化:当 T 是整数类型时,使用特化版本的 print,输出整数类型的大小(以字节为单位)。
- 浮动类型特化:当 T 是浮动类型时,使用特化版本的 print,输出浮动类型的大小。
4、利用 = void 实现类型推导和重载
通过使用 template<typename Func, typename = void>,我们可以根据传入类型的特性来推导不同的行为。= void 作为一个默认模板参数可以帮助我们更好地控制模板重载和特化的匹配,尤其是在类模板中结合其他模板参数进行推导时。
#include <iostream>
#include <type_traits>template<typename T, typename = void>
class MyClass {
public:void foo() {std::cout << "Generic version of foo" << std::endl;}
};// 特化版本:当 T 是指针类型时
template<typename T>
class MyClass<T, typename std::enable_if<std::is_pointer<T>::value>::type> {
public:void foo() {std::cout << "Pointer type version of foo" << std::endl;}
};int main() {MyClass<int> obj1;obj1.foo(); // 输出: Generic version of fooMyClass<int*> obj2;obj2.foo(); // 输出: Pointer type version of foo
}
- 通用版本:对于普通类型 T,MyClass 使用通用版本的 foo 成员函数。
- 指针类型特化:当 T 是指针类型时,MyClass 使用特化版本的 foo 成员函数。
5、结合 std::enable_if 和 std::is_same 实现类型限制
= void 还常常与 std::enable_if 和 std::is_same 等类型特征配合使用,限制模板类的实例化,提供更加灵活的行为。
#include <iostream>
#include <type_traits>template<typename T, typename = void>
class MyClass {
public:void print() {std::cout << "Generic print" << std::endl;}
};// 当 T 是 int 时,使用特化版本
template<typename T>
class MyClass<T, typename std::enable_if<std::is_same<T, int>::value>::type> {
public:void print() {std::cout << "Specialized print for int" << std::endl;}
};int main() {MyClass<double> obj1;obj1.print(); // 输出: Generic printMyClass<int> obj2;obj2.print(); // 输出: Specialized print for int
}
6、总结
template<typename Func, typename = void> 在类模板中的应用,充分体现了 C++ 模板编程的灵活性。通过使用默认模板参数和与 SFINAE 相结合的机制,我们可以实现基于类型特征的模板特化和重载,使得代码更加通用、简洁且具备高度的可扩展性。
相关文章:
template<typename Func, typename = void> 在类模板中的应用
1、基础语法 在 C 中,template<typename Func, typename void> 这一模板声明不仅仅限于函数模板,它在类模板中同样具有强大的应用。结合 SFINAE(Substitution Failure Is Not An Error)和 类型特征(type trait…...
如何确保数据大屏的交互设计符合用户需求?(附实践资料下载)
确保数据大屏的交互设计符合用户需求是一个多步骤的过程,涉及到用户研究、设计原则、原型测试和持续迭代。以下是一些关键步骤和策略: 用户研究: 目标用户识别:明确大屏的目标用户群体,包括他们的背景、角色和需求。用…...
Linux使用教程及常用命令大全
Linux是一个开源的操作系统,具有高度的可定制性和可扩展性。以下是一份 Linux 使用教程及常用命令的总结,帮助你快速入门 Linux。 1. 安装 Linux 下载 Linux 安装程序(可参考我的这篇文章):VMware虚拟机超详细安装Linu…...
基于openlayers 开发vue地图组件
先看效果 主要功能如下: 测量图源更换放大缩小地图添加点hover点数据切换到地图位置;也设定层级2D3D切换,3D为cesium开发,技术交流可以加V:bloxed 地图工具做了插槽,分为toolbar(左上角工具…...
音视频入门基础:AAC专题(13)——FFmpeg源码中,获取ADTS格式的AAC裸流音频信息的实现
音视频入门基础:AAC专题系列文章: 音视频入门基础:AAC专题(1)——AAC官方文档下载 音视频入门基础:AAC专题(2)——使用FFmpeg命令生成AAC裸流文件 音视频入门基础:AAC…...
【C++】B2069 求分数序列和题目解析与优化详解
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯题目描述输入格式输出格式输入输出样例输入:输出: 💯解题思路分析题目解题步骤 💯代码实现我的代码实现实现特点 老师的代码…...
4.FPGA如何实现设计
在前面分别引入了,LUT的知识,全局时钟网络,以及FPGA内部的资源。 LUT的知识: 在FPGA设计中实现的逻辑运算在不借用其他的硬核的基础上都是在LUT中通过查表的方式进行完成的,比如实现的c a & b;就是将a&b的所…...
SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测
SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测(多输入单输出) 目录 SO-CNN-LSTM-MATT蛇群算法优化注意力机制深度学习多特征分类预测(多输入单输出)分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matl…...
大模型-Ollama使用相关的笔记
大模型-Ollama使用相关的笔记 解决Ollama外网访问问题(配置ollama跨域访问)Postman请求样例 解决Ollama外网访问问题(配置ollama跨域访问) 安装Ollama完毕后, /etc/systemd/system/ollama.service进行如下修改&#…...
OpenCV计算机视觉 02 图片修改 图像运算 边缘填充 阈值处理
目录 图片修改(打码、组合、缩放) 图像运算 边缘填充 阈值处理 上一篇文章: OpenCV计算机视觉 01 图像与视频的读取操作&颜色通道 图片修改(打码、组合、缩放) # 图片打码 import numpy as np a cv2.imre…...
langchain使用FewShotPromptTemplate出现KeyError的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...
tryhackme-Cyber Security 101-Linux Shells(linux命令框)
目的:了解脚本和不同类型的 Linux shell。 任务1:Introduction to Linux Shells(Linux Shell 简介) 作为操作系统的常规用户,我们都广泛使用图形用户界面 (GUI) 来执行大多数操作。只需点击几…...
亚远景-ISO 21434标准涵盖了哪些方面?
ISO 21434标准《道路车辆—网络安全工程》全面涵盖了汽车网络安全领域,其目的是确保汽车电子系统在整个产品生命周期中的网络安全性能。具体来说,该标准包括以下几个方面: 1. 术语和定义 :提供汽车网络安全相关的术语、概念和定义…...
第3章 集合与关系
2024年12月24日一稿 2024年12月26日二稿 🐰3.1 集合的概念和表示法 🦘3.1.1 集合的表示 🦘3.1.2 基本概念 🐰3.2 集合的运算 🦘3.2.1 集合的基本运算 🦘3.2.2 有穷计数集 🦘3.2.3 广义交和广义…...
【vmware】|设置共享文件夹
目的: 虚拟机中设置共享文件夹,本地物理机中可以搜到该共享文件夹 1、虚拟机: 设置共享文件夹 右键属性-共享页码进行下列设置 点击网络和共享中心,检查下列选项 二、在本地物理机中启用网络发现: 此时,刷新网络…...
Log4j1.27配置日志输出级别不起效
起因:构建独立版本debezuim使用时,日志一直打印debug信息。 原因:包冲突问题,进行排包操作。 参考log4j日志级别配置完成后不生效 系统一直打印debug日志_log4j不起作用-CSDN博客 1、application.properties logging.configc…...
计算机图形学知识点汇总
一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中,“形”指形体或形状,存在于客观世界和虚拟世界,它的本质是“表示”;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面,用于表达…...
详解下c语言中struct和union的对齐规则
接触过c语言的同学应该都知道字节对齐。有些时候我们很容易弄错字节对齐的方式,特别是涉及到struct(结构体)和union(联合体)时。今天我们通过详细例子来说明下struct和union的对齐规则,以便了解各种struct和…...
ubuntu安装sublime安装与免费使用
1. ubuntu安装sublime 参考官网: Linux Package Manager Repositories 2. 破解过程 打开如下网址,打开/opt/sublime_text/sublime_text https://hexed.it/ 3. 替换在hexed打开的文件中查找并替换: 4180激活方法 使用二进制编辑器 8079 0500 0f94 c2替换为 c641 05…...
攻防世界 cookie
开启场景 Cookie(HTTP cookie)是一种存储在用户计算机上的小型文本文件。它由网站通过用户的浏览器在用户访问网站时创建,并存储一些用于跟踪和识别用户的信息。Cookie 主要用于在网站和浏览器之间传递数据,以便网站可以根据用户的…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
