C++ 模板进阶知识——stdenable_if
目录
- C++ 模板进阶知识——std::enable_if
- 1. 简介和背景
- 基本语法
- 使用场景
- 2. `std::enable_if` 的基本用法
- 示例:限制函数模板只接受整数类型
- 3. SFINAE 和 std::enable_if
- 示例:使用 SFINAE 进行函数重载
- SFINAE 的优点
- 应用场景
- 4. 在类模板中使用 std::enable_if
- 示例:根据类型特性特化类模板
- 5. 使用 std::enable_if 启用成员函数
- 总结
C++ 模板进阶知识——std::enable_if
在 C++ 的模板编程中,控制模板的实例化是关键且复杂的一部分。std::enable_if 是一个模板元编程工具,用于基于编译时条件(如类型特征)来启用或禁用模板代码。这种技术不仅增强了代码的灵活性,还提高了类型安全性,是现代 C++ 开发者必须掌握的技能之一。
1. 简介和背景
std::enable_if 可以根据布尔表达式的结果来启用或者禁用特定的函数重载或模板实例化。这一特性在泛型编程中尤其有用,它允许开发者基于类型特性动态地选择合适的模板重载。这是通过 SFINAE(Substitution Failure Is Not An Error)原则实现的,该原则表明,如果某个模板参数替换失败,并不会导致错误,而是简单地导致该模板候选被丢弃。
基本语法
std::enable_if 的基本形式如下:
std::enable_if<condition, type>::type
condition是一个编译时可求值的表达式,结果为布尔值。type是当条件为true时,enable_if将产生的类型。如果不指定type,默认为void。
使用场景
- 函数模板重载:根据类型特性选择合适的函数版本。
- 类模板特化:根据类型条件进行模板特化。
- 成员函数启用:仅当满足某些条件时才使成员函数可用。
2. std::enable_if 的基本用法
std::enable_if 的典型用法是作为函数模板的返回类型,或者作为类模板或函数模板的模板参数。
示例:限制函数模板只接受整数类型
#include <iostream>template<typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
is_odd(T i) {return bool(i % 2);
}int main() {std::cout << "Is 5 odd? " << is_odd(5) << std::endl;// 下面的代码会因为类型错误而无法编译// std::cout << "Is pi odd? " << is_odd(3.14) << std::endl;
}
这个例子中,is_odd 函数模板使用 std::enable_if 来确保它只能用于整数类型。如果尝试用非整数类型调用 is_odd,将会导致编译错误,这有助于早期捕捉潜在的类型错误。
3. SFINAE 和 std::enable_if
SFINAE(Substitution Failure Is Not An Error)是 C++ 中一个重要的编译时概念,它对于模板编程尤其关键。SFINAE 允许在模板参数替换过程中发生的失败不被视为错误,而是简单地导致该候选模板被排除在外。这种特性使得开发者能够编写更加灵活和强大的模板代码,尤其是在进行模板重载和特化时。
std::enable_if 是实现 SFINAE 的一种常用工具。它可以根据编译时的条件(通常是类型特征)来启用或禁用模板代码。这种技术可以用于控制函数模板的重载、类模板的特化,以及其他模板行为。
示例:使用 SFINAE 进行函数重载
下面这个示例,其中使用 std::enable_if 来创建两个重载的模板函数,一个处理整数,另一个处理浮点数:
#include <iostream>template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
process(T value) {std::cout << "Processing integral type: " << value << std::endl;return value * 2;
}template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
process(T value) {std::cout << "Processing floating point type: " << value << std::endl;return value / 2;
}int main() {process(10); // 调用处理整数类型的函数版本process(3.14); // 调用处理浮点数类型的函数版本
}
在这个例子中,根据传递给 process 函数的参数类型,编译器会选择合适的重载版本。如果类型匹配失败,则不视为错误,而是继续寻找其他匹配的重载。
SFINAE 的优点
- 类型安全:通过在编译时就排除不适合的类型,可以提高代码的安全性。
- 灵活性:能够针对不同的类型条件编写专门的模板代码,增加代码的灵活性和可重用性。
- 可维护性:通过将特定操作限制在适当的类型上,可以简化代码逻辑,使得代码更易维护。
应用场景
SFINAE 和 std::enable_if 在很多高级 C++ 应用和库中都有广泛应用,例如 STL(标准模板库)中就大量使用了这种技术来处理不同类型的数据。此外,它们也常见于需要高度类型特化的框架和库中,如数值计算库、图形处理库等。
4. 在类模板中使用 std::enable_if
std::enable_if 可以用作类模板的偏特化条件,允许根据类型特性(如是否是整数、浮点数、指针等)来选择不同的模板特化。这种方式特别适用于需要对不同类型执行不同操作的情况,如数值计算、资源管理等领域。
示例:根据类型特性特化类模板
一个简单的例子,建一个名为 TypeClassifier 的类模板,该模板根据其模板参数是整数类型还是浮点类型来打印不同的消息:
#include <iostream>template<typename T, typename Enable = void>
class TypeClassifier;// 特化对于整数类型
template<typename T>
class TypeClassifier<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:static void classify() {std::cout << "Integral type" << std::endl;}
};// 特化对于浮点类型
template<typename T>
class TypeClassifier<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:static void classify() {std::cout << "Floating point type" << std::endl;}
};int main() {TypeClassifier<int>::classify(); // 输出 "Integral type"TypeClassifier<double>::classify(); // 输出 "Floating point type"
}
在这个例子中,TypeClassifier 类模板有两个特化版本:一个用于整数类型,另一个用于浮点类型。通过使用 std::enable_if,我们能够确保每个特化版本只适用于正确的类型。
5. 使用 std::enable_if 启用成员函数
以下是一个使用 std::enable_if 来启用特定成员函数的示例,这里定义了一个模板类 ArrayPrinter,它包含两个成员函数 print。一个用于打印整数数组,另一个用于打印浮点数数组,每个函数只在其模板类型满足相应条件时才可用。
#include <iostream>
#include <type_traits>
#include <vector>template <typename T>
class ArrayPrinter {
public:// 仅当T是整数类型时启用此函数template <typename U = T>typename std::enable_if<std::is_integral<U>::value, void>::typeprint(const std::vector<U>& arr) {std::cout << "Integer array: ";for (auto elem : arr) {std::cout << elem << " ";}std::cout << std::endl;}// 仅当T是浮点数类型时启用此函数template <typename U = T>typename std::enable_if<std::is_floating_point<U>::value, void>::typeprint(const std::vector<U>& arr) {std::cout << "Floating point array: ";for (auto elem : arr) {std::cout << elem << " ";}std::cout << std::endl;}
};int main() {ArrayPrinter<int> intPrinter;ArrayPrinter<double> doublePrinter;std::vector<int> intArray = {1, 2, 3, 4};std::vector<double> doubleArray = {1.1, 2.2, 3.3, 4.4};intPrinter.print(intArray); // 输出: Integer array: 1 2 3 4doublePrinter.print(doubleArray); // 输出: Floating point array: 1.1 2.2 3.3 4.4
}
在这个例子中,ArrayPrinter 类模板定义了两个 print 方法,每个方法都使用了 std::enable_if 来限制其适用的数据类型。这样做确保了整数打印方法仅对整数类型的 ArrayPrinter 实例可用,而浮点打印方法仅对浮点类型的实例可用。
总结
std::enable_if 是 C++ 模板编程中一个强大的工具,它通过允许基于编译时条件控制模板的实例化,帮助开发者编写更精确、更高效的代码。掌握这一工具对于任何需要进行高级模板编程的 C++ 开发者来说都是至关重要的。
相关文章:
C++ 模板进阶知识——stdenable_if
目录 C 模板进阶知识——std::enable_if1. 简介和背景基本语法使用场景 2. std::enable_if 的基本用法示例:限制函数模板只接受整数类型 3. SFINAE 和 std::enable_if示例:使用 SFINAE 进行函数重载SFINAE 的优点应用场景 4. 在类模板中使用 std::enable…...
国内外ChatGPT网站集合,无限制使用【2024-09最新】~
经过我一年多以来,使用各种AI工具的体验,我收集了一批AI工具和站点 这些工具都是使用的最强最主流的模型,也都在各个领域里都独领风骚的产品。 而且,这些工具你都可以无限制地使用。 无论你是打工人、科研工作者、学生、文案写…...
如何在VUE3中使用函数式组件
在Vue 3中,函数式组件的概念与Vue 2相似,但实现方式有所不同。函数式组件是一种无状态、无实例的组件,它们只根据传入的props和context来渲染输出。在Vue 3中,你可以通过定义一个函数并返回一个渲染函数来使用函数式组件。但是&am…...
linux访问外网的设置
Ubuntu | LUCKFOX WIKI 开发板配置 添加路由信息 sudo route add default gw 172.32.0.100添加 DNS servers 打开文件 sudo vi /etc/resolv.conf添加以下内容: nameserver 8.8.8.8联网测试 ping www.baidu.com开机自动配置 路由信息和 DNS servers 重启后会被清除,我们创建…...
PHP轻松创建高效收集问卷调查小程序系统源码
轻松创建,高效收集 —— 问卷调查小程序,你的调研神器! 一、告别繁琐,一键开启调研之旅 还在为设计问卷、收集数据而头疼不已吗?现在,有了“问卷调查小程序”,一切都变得轻松简单!无…...
Redis面试必问:Redis为什么快?Redis五大基本数据类型
请记住胡广一句话,所有的中间件所有的框架都是建立在基础之上,数据结构,计算机网络,计算机原理大伙一定得看透!!~ 1. Redis快的秘密 相信大部分Redis初学者都会忽略掉一个重要的知识点,Redis…...
InternVL2- dockerfile环境变量持久化使用`ENV`而不是`RUN export`来设置环境变量,以确保环境变量在容器运行时仍然可用
在Dockerfile中使用RUN export命令设置环境变量并不是一种持久化的方式。当你在Dockerfile中使用export命令时,它只会在当前构建阶段生效,并不会被持久化到生成的镜像中。这是因为export命令实际上是在shell环境中设置环境变量,而Docker构建过…...
Python(PyTorch和TensorFlow)图像分割卷积网络导图(生物医学)
🎯要点 语义分割图像三层分割椭圆图像脑肿瘤图像分割动物图像分割皮肤病变分割多模态医学图像多尺度特征生物医学肖像多类和医学分割通用图像分割模板腹部胰腺图像分割分类注意力网络病灶边界分割气胸图像分割 Python生物医学图像卷积网络 该网络由收缩路径和扩…...
DevOps实现CI/CD实战(七)- Jenkins集成k8s实现自动化CI
自动化CI操作 1. 安装gitlab plugin 工具 ##### 2. 配置流水线任务的构建触发器,复制URL:http://192.168.201.111:8080/project/pipeline 3. Gitlab配置Webhooks,将上面的url:http://192.168.201.111:8080/project/pipeline粘…...
从ES6到ES2023 带你深入了解什么是ES
从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功…...
openVX加速-常见问题:适用场景、AI加速、安装方式等
1. 哪些算法处理推荐使用 OpenVX OpenVX 是非常适合图像处理和计算机视觉任务的框架,特别是在需要高性能和硬件加速的场景下。如果你的前处理和后处理涉及到图像滤波、边缘检测、颜色转换等操作,使用 OpenVX 可以带来性能提升。 OpenVX 更适合处理以下…...
国产芯片LT8711HE:TYPE-C/DP1.2转HDMI2.0转换器,4k60Hz高分辨率
以下为LT8711HE芯片的简单介绍,如有介绍不尽之处,请指出 LT8711HE是一个高性能的Type-C/DP1.2到HDMI2.0转换器,用于连接USB Type-C源或DP1.2源到HDMI2.0接收器。 LT8711HE集成了一个DP1.2兼容的接收器和一个HDMI2.0兼容的发射器。另外&…...
论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey
Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs&…...
Java+Swing用户信息管理系统
JavaSwing用户信息管理系统 一、系统介绍二、功能展示1.管理员登陆2.用户信息查询3.用户信息添加4.用户信息修改5.用户信息删除 三、系统实现1.UserDao .java 四、其它1.其他系统实现 一、系统介绍 该系统实现了管理员系统登陆、用户信息查询、用户信息添加、用户信息修改、用…...
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值特殊矩阵的压缩存储
文章目录 栈的应用1.栈的括号匹配代码实战:问题分析:2.栈的表达式求值2.1 中缀、后缀、前缀表达式2.2 中缀表达式改写为后缀表达式(手算)2.3 后缀表达式的计算(手算)2.4 中缀表达式转前缀表达式(手算)和计算前缀表达式2.5后缀表达式的计算(机算)2.6 中缀表达式转后缀…...
C# 关于多线程同步不同实现方式
栏目总目录 AutoResetEvent class MainClass {// the array of consumer threadsprivate static List<Thread> consumers new List<Thread> ();// the task queueprivate static Queue<Action> tasks new Queue<Action>();// the synchronisation o…...
【人工智能学习笔记】4_2 深度学习基础之多层感知机
感知机概述 感知机是人工智能最早的模型,是一种有监督的算法,本质上是一个二分类问题,是神经网络和支持向量机的基础缺点:感知机智能解决单纯的线性问题 感知机的过程 多层感知机的层级结构 多层感知机的层级结构主要包括输入层、隐藏层和输出层、可以用于拟合非线性函数。…...
WPS2019如何打出各种横线
WPS2019如何打出各种横线 测试于WPS2019...
Vue获取后端重定向拼接的参数
前言 比如我们要重定向这样一个连接: http://192.168.2.189:8081?nameadmin springboot重定向: Vue获取: getParam(param) {var reg new RegExp("(^|&)" param "([^&]*)(&|$)");var r location.searc…...
vscode spring boot项目编辑yaml不自动提示补全如何解决
文章目录 properties能够自动弹出提示但是YAML文件就不会自动弹出提示ctrl空格不出提示的解决办法 properties能够自动弹出提示 但是YAML文件就不会自动弹出提示 只是不会自动弹出来而已,按ctrl空格即可解决 ctrl空格不出提示的解决办法 如果按ctrl空格没有用 …...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
