当前位置: 首页 > 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空格没有用 …...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...