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

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

使用场景

  1. 函数模板重载:根据类型特性选择合适的函数版本。
  2. 类模板特化:根据类型条件进行模板特化。
  3. 成员函数启用:仅当满足某些条件时才使成员函数可用。

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 的优点

  1. 类型安全:通过在编译时就排除不适合的类型,可以提高代码的安全性。
  2. 灵活性:能够针对不同的类型条件编写专门的模板代码,增加代码的灵活性和可重用性。
  3. 可维护性:通过将特定操作限制在适当的类型上,可以简化代码逻辑,使得代码更易维护。

应用场景

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 的基本用法示例&#xff1a;限制函数模板只接受整数类型 3. SFINAE 和 std::enable_if示例&#xff1a;使用 SFINAE 进行函数重载SFINAE 的优点应用场景 4. 在类模板中使用 std::enable…...

国内外ChatGPT网站集合,无限制使用【2024-09最新】~

经过我一年多以来&#xff0c;使用各种AI工具的体验&#xff0c;我收集了一批AI工具和站点 这些工具都是使用的最强最主流的模型&#xff0c;也都在各个领域里都独领风骚的产品。 而且&#xff0c;这些工具你都可以无限制地使用。 无论你是打工人、科研工作者、学生、文案写…...

如何在VUE3中使用函数式组件

在Vue 3中&#xff0c;函数式组件的概念与Vue 2相似&#xff0c;但实现方式有所不同。函数式组件是一种无状态、无实例的组件&#xff0c;它们只根据传入的props和context来渲染输出。在Vue 3中&#xff0c;你可以通过定义一个函数并返回一个渲染函数来使用函数式组件。但是&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轻松创建高效收集问卷调查小程序系统源码

轻松创建&#xff0c;高效收集 —— 问卷调查小程序&#xff0c;你的调研神器&#xff01; 一、告别繁琐&#xff0c;一键开启调研之旅 还在为设计问卷、收集数据而头疼不已吗&#xff1f;现在&#xff0c;有了“问卷调查小程序”&#xff0c;一切都变得轻松简单&#xff01;无…...

Redis面试必问:Redis为什么快?Redis五大基本数据类型

请记住胡广一句话&#xff0c;所有的中间件所有的框架都是建立在基础之上&#xff0c;数据结构&#xff0c;计算机网络&#xff0c;计算机原理大伙一定得看透&#xff01;&#xff01;~ 1. Redis快的秘密 相信大部分Redis初学者都会忽略掉一个重要的知识点&#xff0c;Redis…...

InternVL2- dockerfile环境变量持久化使用`ENV`而不是`RUN export`来设置环境变量,以确保环境变量在容器运行时仍然可用

在Dockerfile中使用RUN export命令设置环境变量并不是一种持久化的方式。当你在Dockerfile中使用export命令时&#xff0c;它只会在当前构建阶段生效&#xff0c;并不会被持久化到生成的镜像中。这是因为export命令实际上是在shell环境中设置环境变量&#xff0c;而Docker构建过…...

Python(PyTorch和TensorFlow)图像分割卷积网络导图(生物医学)

&#x1f3af;要点 语义分割图像三层分割椭圆图像脑肿瘤图像分割动物图像分割皮肤病变分割多模态医学图像多尺度特征生物医学肖像多类和医学分割通用图像分割模板腹部胰腺图像分割分类注意力网络病灶边界分割气胸图像分割 Python生物医学图像卷积网络 该网络由收缩路径和扩…...

DevOps实现CI/CD实战(七)- Jenkins集成k8s实现自动化CI

自动化CI操作 1. 安装gitlab plugin 工具 ##### 2. 配置流水线任务的构建触发器&#xff0c;复制URL&#xff1a;http://192.168.201.111:8080/project/pipeline 3. Gitlab配置Webhooks&#xff0c;将上面的url&#xff1a;http://192.168.201.111:8080/project/pipeline粘…...

从ES6到ES2023 带你深入了解什么是ES

从ES6到ES2023&#xff0c;我们深入探索ECMAScript&#xff08;简称ES&#xff09;的演变与发展&#xff0c;了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本&#xff0c;每年都在不断推出新版本&#xff0c;为开发者带来更加丰富和强大的功…...

openVX加速-常见问题:适用场景、AI加速、安装方式等

1. 哪些算法处理推荐使用 OpenVX OpenVX 是非常适合图像处理和计算机视觉任务的框架&#xff0c;特别是在需要高性能和硬件加速的场景下。如果你的前处理和后处理涉及到图像滤波、边缘检测、颜色转换等操作&#xff0c;使用 OpenVX 可以带来性能提升。 OpenVX 更适合处理以下…...

国产芯片LT8711HE:TYPE-C/DP1.2转HDMI2.0转换器,4k60Hz高分辨率

以下为LT8711HE芯片的简单介绍&#xff0c;如有介绍不尽之处&#xff0c;请指出 LT8711HE是一个高性能的Type-C/DP1.2到HDMI2.0转换器&#xff0c;用于连接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 大规模语言模型的基准数据污染&#xff1a;一项综述 文章目录 大规模语言模型的基准数据污染&#xff1a;一项综述摘要1 引言 摘要 大规模语言模型&#xff08;LLMs&…...

Java+Swing用户信息管理系统

JavaSwing用户信息管理系统 一、系统介绍二、功能展示1.管理员登陆2.用户信息查询3.用户信息添加4.用户信息修改5.用户信息删除 三、系统实现1.UserDao .java 四、其它1.其他系统实现 一、系统介绍 该系统实现了管理员系统登陆、用户信息查询、用户信息添加、用户信息修改、用…...

数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值特殊矩阵的压缩存储

文章目录 栈的应用1.栈的括号匹配代码实战:问题分析:2.栈的表达式求值2.1 中缀、后缀、前缀表达式2.2 中缀表达式改写为后缀表达式(手算)2.3 后缀表达式的计算(手算)2.4 中缀表达式转前缀表达式&#xff08;手算)和计算前缀表达式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获取后端重定向拼接的参数

前言 比如我们要重定向这样一个连接&#xff1a; http://192.168.2.189:8081?nameadmin springboot重定向&#xff1a; Vue获取&#xff1a; getParam(param) {var reg new RegExp("(^|&)" param "([^&]*)(&|$)");var r location.searc…...

vscode spring boot项目编辑yaml不自动提示补全如何解决

文章目录 properties能够自动弹出提示但是YAML文件就不会自动弹出提示ctrl空格不出提示的解决办法 properties能够自动弹出提示 但是YAML文件就不会自动弹出提示 只是不会自动弹出来而已&#xff0c;按ctrl空格即可解决 ctrl空格不出提示的解决办法 如果按ctrl空格没有用 …...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...

【若依】框架项目部署笔记

参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作&#xff1a; 压缩包下载&#xff1a;http://download.redis.io/releases 1. 上传压缩包&#xff0c;并进入压缩包所在目录&#xff0c;解压到目标…...

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...

java 局域网 rtsp 取流 WebSocket 推送到前端显示 低延迟

众所周知 摄像头取流推流显示前端延迟大 传统方法是服务器取摄像头的rtsp流 然后客户端连服务器 中转多了&#xff0c;延迟一定不小。 假设相机没有专网 公网 1相机自带推流 直接推送到云服务器 然后客户端拉去 2相机只有rtsp &#xff0c;边缘服务器拉流推送到云服务器 …...