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

C++模板元一生之友之:std::enable_if

你可以不懂模板元,但是你一定要懂enable_if, 因为你身边的朋友都悄悄地学会了enable_if, 并且让别人读不懂自己看起来很高端的代码。

std::enable_if 是 C++11 引入的一个工具,用于在编译时进行条件选择。它主要用来实现模板的 SFINAE(Substitution Failure Is Not An Error)机制,即在模板参数替换失败时不作为错误处理,而是选择其他可行的模板实例化。std::enable_if 常用于函数模板、类模板和重载中,以根据编译时条件启用或禁用特定的模板实例化。

std::enable_if 的基本用法

std::enable_if 位于 <type_traits> 头文件中,主要有两个模板参数:

  • 一个布尔条件 B
  • 一个类型 T,默认值为 void

如果 Btrue,则 std::enable_if<B, T>::type 定义为 T;如果 Bfalse,则 std::enable_if<B, T>::type 没有定义。

template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Testtemplate <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Testusing type = _Ty;
};

根据返回值选择模板

在如下示例中,foo 函数模板有两个重载版本,一个用于整数类型,一个用于浮点类型。std::enable_if 用于选择合适的模板实例化。【严格来说,这并不叫做函数重载版本,而是两个函数模板】

#include <type_traits>
#include <iostream>// 只在T是整数类型时启用此函数
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
foo(T value) {return value * 2;
}// 只在T是浮点类型时启用此函数
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
foo(T value) {return value * 0.5;
}int main() {std::cout << foo(10) << std::endl;    // 输出20std::cout << foo(10.5) << std::endl;  // 输出5.25return 0;
}

根据模板参数类型进行重载

在下面示例中, 根据参数类型进行函数版本选择。

template<class T, typename std::enable_if_t<std::is_enum_v<T>, bool> = true >
void write(const T& t)
{std::cout << "write enum type" << std::endl;
}//函数模板如果写成下面形式,可能更容易理解,这里给模板参数默认值,是为了调用函数不必传两个模板参数。
//template<class T, typename std::enable_if_t<std::is_enum_v<T>, bool> Flag = true >template<class T, typename std::enable_if_t<!std::is_enum_v<T>, bool> = true>
void  write(const T& t)
{std::cout << "write non - enum typ" << std::endl;
}enum MyEnum
{ONE = 1,TWO = 2
};int main() {write(100); // write non - enum typMyEnum my_enum;write(my_enum); // write enum typereturn 0;
}

在类模板中的使用

std::enable_if 也可以在类模板中使用,以控制类模板的部分或全部实例化。在下面示例中,MyClass 类模板有两个特化版本:一个用于整数类型,一个用于浮点类型。std::enable_if 用于控制特化版本的选择。

#include <type_traits>
#include <iostream>// 只在T是整数类型时启用此类模板
template<typename T, typename Enable = void>
class MyClass;// 特化版本:T是整数类型时, 这里特化版也是MyClass<T, void>,但会优先匹配到这个特化版
template<typename T>
class MyClass<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:
void display() {std::cout << "Integral type" << std::endl;
}
};// 特化版本:T是浮点类型时,这里特化版也是MyClass<T, void>,但会优先匹配到这个特化版
template<typename T>
class MyClass<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
void display() {std::cout << "Floating point type" << std::endl;
}
};int main() {MyClass<int> intClass;intClass.display(); // 输出:Integral typeMyClass<double> floatClass;floatClass.display(); // 输出:Floating point typereturn 0;
}

std::enable_if 是一种强大的工具,用于在编译时根据条件启用或禁用模板实例化。这对于编写通用的、类型安全的模板代码非常有用。通过结合 std::enable_if 与类型特性(如 std::is_integralstd::is_floating_point 等),可以实现非常灵活的模板编程。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 若依vue版前端白名单处理
  • php之 进行签名公钥、私钥(SHA1withRSA签名)
  • oracle(19c)用户管理
  • pytorch学习笔记3 tensor索引和切片
  • 如何使用哔哩哔哩下载与缓存视频?
  • 【无标题】图像增强技术:直方图均衡化、拉普拉斯算子、对数变换与伽马变换
  • Markdown语法学习
  • 同一台机器上,github多账号操作
  • HPC高性能计算平台
  • 体验 Whisper ,本地离线部署自己的 ASR 语音识别服务
  • 【第六章】测试理论与方法 - 灰盒测试的深入解析
  • SpringBoot 集成原生 Servlet、Filter、Listener
  • upload-labs漏洞靶场~文件上传漏洞
  • 【优秀python案例】基于python爬虫的深圳房价数据分析与可视化实现
  • Leetcode3227. 字符串元音游戏
  • CentOS 7 防火墙操作
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Koa2 之文件上传下载
  • Spring声明式事务管理之一:五大属性分析
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 阿里云应用高可用服务公测发布
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 从重复到重用
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 问题之ssh中Host key verification failed的解决
  • 我的zsh配置, 2019最新方案
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​渐进式Web应用PWA的未来
  • #includecmath
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (2)STL算法之元素计数
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (BFS)hdoj2377-Bus Pass
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (接上一篇)前端弄一个变量实现点击次数在前端页面实时更新
  • (十三)Flink SQL
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (四) Graphivz 颜色选择
  • (四)Controller接口控制器详解(三)
  • (转)Oracle存储过程编写经验和优化措施
  • (转)大道至简,职场上做人做事做管理
  • *p++,*(p++),*++p,(*p)++区别?
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .net dataexcel 脚本公式 函数源码
  • .Net6使用WebSocket与前端进行通信
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .NET中统一的存储过程调用方法(收藏)
  • [ SNOI 2013 ] Quare
  • [.NET 即时通信SignalR] 认识SignalR (一)
  • []使用 Tortoise SVN 创建 Externals 外部引用目录