C++11模板元编程—std::enable_if使用说明

2023-11-08

std::enable_if 顾名思义,满足条件时类型有效。作为选择类型的小工具,其广泛的应用在 C++ 的模板元编程中。它的定义也非常的简单:

// STRUCT TEMPLATE enable_if
template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Test

template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
    using type = _Ty;
};

由此可知,只有当第一个模板参数_Testtrue 时,type 才有定义(type即第二个模板参数_Ty);否则使用 type 会产生编译错误,且默认模板参数可以让你不必指定类型。

另外enable_if_t是一个别名,其定义如下:

template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;

std::enable_if可以用作函数参数、返回类型或类模板或函数模板参数,以有条件地从重载中删除函数或类。

一、作为函数参数

template<typename T>
struct Check1
{
    //如果T的类型是int,则定义函数 int read(void* = nullptr)
	template<typename U = T>
	U read(typename std::enable_if_t<std::is_same_v<U, int> >* = nullptr) {
		return 42;
	}
    
    //如果T的类型是double,则定义函数 double read(void* = nullptr)
	template<typename U = T>
	U read(typename std::enable_if_t<std::is_same_v<U, double> >* = nullptr) {
		return 3.14;
	}
};

使用示例

Check1<int> c1;
int x1 = c1.read();

Check1<double> c2;
double x2 = c2.read(0);

二、作为模板参数

template<typename T>
struct Check2
{
    //如果T的类型是int,则定义函数 int read()
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, int>, int> = 0>
	U read() {
		return 42;
	}
    
    //如果T的类型是double,则定义函数 double read()
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, double>, int> = 0>
	U read() {
		return 3.14;
	}
};

也可以写成如下形式:

template<typename T>
struct Check2
{
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, int>>* = nullptr>
	U read() {
		return 42;
	}

	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, double>>* = nullptr>
	U read() {
		return 3.14;
	}
};

三、作为返回值类型

对于模板函数,有时希望根据不同的模板参数返回不同类型的值。

template<typename T>
struct Check3
{
    //如果T的类型是int,则定义函数 int read()
	template<typename U = T>
	typename std::enable_if_t<std::is_same_v<U, int>, U> read() {
		return 42;
	}

    //如果T的类型是double,则定义函数 double read()
	template<typename U = T>
	typename std::enable_if_t<std::is_same_v<U, double>, U> read() {
		return 3.14;
	}
};

利用auto关键字,可以写为如下形式:

// int goo<true>(int x)
template<bool B>
auto goo(int x) -> std::enable_if_t<B, int>
{
	return 1;
}

// int goo<false>(int x)
template<bool B>
auto goo(int x) -> std::enable_if_t<!B, int>
{
	return 2;
}

四、类型偏特化

在使用模板编程时,经常会用到根据模板参数的某些特性进行不同类型的选择,或者在编译时校验模板参数的某些特性。例如:

// T是其它类型
template<typename T, typename = void>
struct zoo;

// 如果T是浮点类型
template<typename T>
struct zoo<T, std::enable_if_t<std::is_integral_v<T>>>
{
};

五、concepts

C++20中利用concepts可以简化编写方式:

#ifdef __cpp_lib_concepts
#include <concepts>
#endif

// 如果T是整数类型
template<std::integral T>
void display_concepts_1(T num)
{
}

// 如果T是整数类型
void display_concepts(std::integral auto num)
{
}

// 如果T是浮点数类型
void display_concepts(std::floating_point auto num)
{
}

等价于如下形式:

// 如果T是整数类型
template<typename T, typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
void display_1(T num)
{
}

// 如果T是整数类型
template<typename T>
void display(typename std::enable_if_t<std::is_integral_v<T>>* = nullptr)
{
}

// 如果T是浮点数类型
template<typename T>
void display(typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr)
{
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11模板元编程—std::enable_if使用说明 的相关文章

  • 编译时运算符

    有人可以列出 C 中可用的所有编译时运算符吗 C 中有两个运算符 无论操作数如何 它们的结果始终可以在编译时确定 它们是sizeof 1 and 2 当然 其他运算符的许多特殊用途可以在编译时解决 例如标准中列出的那些整数常量表达式 1 与
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • 赛灵思FPGA编程入门指南

    中英双语字幕精校版 赛灵思FPGA编程入门之新手指南第1集 什么是FPGA 现场可编程门阵列 FPGA概念 什么是FPGA 现场可编程门阵列 FPGA概念 本系列视频旨在为FPGA新人逐步讲解教程和基本概念 提供FPGA编程入门指导 帮助您
  • web程序员表白程序,三行情书

    Git项目地址 loveLetter 很久之前的作品 用JS和CSS3实现的 今天给大家分享一部分 若要见完整版 请点击右侧链接下载 程序员浪漫表白 三行情书 一等奖 JS CSS3 注 这是一个3D场景 在PC端的话还可以按住鼠标左键并拖
  • 数据库-sqlserver数据库迁移到mysql

    文章目录 前言 流程 前言 有时一些sqlserver的数据库需要迁移到mysql上 流程 管理员方式启动mysql的sqlYOG图形化界面 右键对象浏览器导入外部数据库 此处点下一步没有用的 需要先建立dsn 给要建立的dsn文件起个名字
  • 申请被拒模板 (五)

    这里只是模板 仅供学习 出现任何问题 与博主无关 Hi XXXX Thank you for your interest We appreciate the time you took to apply with us At this ti
  • h2 mysql 比较_h2 数据库时间比较

    时间比较的格式是 parsedatetime imp time yyyy MM dd hh mm ss en GMT gt parsedatetime 2012 06 07 00 00 00 yyyy MM dd hh mm ss en G
  • 多态、object类、package、Integer类、String和int类型之间的转换

    多态 多态即为事物存在的多种形态 多态存在的前提 要有继承关系 要有方法的重写 父类引用指向子类对象 多态中的成员访问特点 成员变量 编译看左边 父类 运行看左边 父类 成员方法 编译看左边 父类 运行看右边 子类 静态方法 编译看左边 父
  • MySQL使用binlog日志做数据恢复

    MySQL的binlog日志是MySQL日志中非常重要的一种日志 记录了数据库所有的DML操作 通过binlog日志我们可以进行数据库的读写分离 数据增量备份以及服务器宕机时的数据恢复 定期备份固然可以在服务器发生宕机的时候快速的恢复数据
  • 使用MyJRebel获取免费的JRebel授权

    在我们开发Java Web程序的时候 调试就是一个麻烦事情 每次更改类 就需要重启服务器 对于Tomcat这样的小巧服务器来说 重启就重启吧 反正也就是几秒钟的事情 如果使用的是完整的Java EE标准服务器 GlassFish这种 重启的
  • 权威分析@RequestParam和@RequestPart 的区别(官方文档)

    一 今天写了两个文件上传的接口用到了 RequestParam和 RequestPart RequestPart 单文件上传 param file param bucket return RequestMapping uploadFile
  • Java50个关键字总结

    作业一 Java基础知识复习 一 关键字总结 1 abstract 修饰类 abstract修饰类 这个类就是抽象类 抽象类中可以有非抽象变量和成员变量 也可以有普通方法 构造方法 但是不能实例化 只能被子类继承 如果子类不是抽象类 则必须
  • python出现invalid syntax什么意思_关于Python出现invalid syntax的几种原因

    原博文 2020 03 19 16 41 1 语法错误 3 X和2 X的语法区别非常大 需要多去了解之后再下手 2 代码缩进问题 这个一般用到工具的情况下可以自动调整 3 我今天也就是傻乎乎的犯了 安装命令是在cmd下直接运行 并不是在py
  • 输入字符串型数字,将字符串型数字转化为整型数字,再将整型数字转化为字符串数字的数组,数字字符串相互转化

    输入字符串型数字 将字符串型数字转化为整型数字 再将整型数字转化为字符串数字的数组 写此函数的原因 很多题目都是对字符串的操作 特别是若能将字符串和数字相互转化 那么解题就会方便很多 直接上代码 有注释 include
  • CreateWindowEx详解

    语法 HWND CreateWindowEx DWORD dwExStyle LPCTSTR lpClassName LPCTSTR lpWindowName DWORD dwStyle int x int y int nWidth int
  • cmd命令查看笔记本电池状况

    1 以管理员身份运行 打开 命令提示符 exe 2 在命令提示符输入 powercfg batteryreport output D battery report html 其中 引号内的电池使用报告文件的保存路径可以自定义 你也可以保存到
  • linux根据进程的运行路径,停止进程

    公式 lsof grep 路径 awk print 2 xargs kill 比如我想停掉目录 home code python program 下的程序 可以使用 lsof grep home code python program aw
  • Python简介与安装

    一 windows下安装python 二 linux下安装python 三 mac系统安装python 四 学会配置不同操作系统的环境变量 windows配置环境变量 linux配置环境变量 五 写一个简单的helloworld小程序 学会
  • Python基于Zmail发送邮件

    目录 一 介绍 二 安装 三 使用须知 四 使用步骤 4 1 获得邮件授权码 以QQ邮箱为例 4 2 发送简单文本邮件 4 3 发送Html文件邮件 4 4 发送文本txt文件邮件 4 4 发送带附件邮件 4 5 验证SMTP和POP功能是
  • 了解GFS和HDFS后,要懂得分布式文件系统设计原理

    转自 https www jianshu com p fc0aa34606ce 一 概述 分布式文件系统是分布式领域的一个基础应用 其中最著名的毫无疑问是 HDFS GFS 如今该领域已经趋向于成熟 但了解它的设计要点和思想 对我们将来面临
  • 伸缩自如的ElasticSearch——通过bboss操作和访问elasticsearch模式

    文章目录 ClientUtil 加载配置文件中的dsl来实现对es的操作模式 所有不依赖dsl的功能 或直接接收dsl模式 基本功能 配置es查询dsl 文档批量创建或者修改 http api 查询dsl动态脚本语法规范 配置springb
  • C++11模板元编程—std::enable_if使用说明

    std enable if 顾名思义 满足条件时类型有效 作为选择类型的小工具 其广泛的应用在 C 的模板元编程中 它的定义也非常的简单 STRUCT TEMPLATE enable if template