enable_if<>这个概念,以前从没有遇到过,这里做个小记。

/*----------llvm/include/llvm/ADT/Hashing.h------------*/
/// \brief Compute a hash_code for any integer value.
///
/// Note that this function is intended to compute the same hash_code for
/// a particular value without regard to the pre-promotion type. This is in
/// contrast to hash_combine which may produce different hash_codes for
/// differing argument types even if they would implicit promote to a common
/// type without changing the value.

template <typename T>
typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
hash_value(T value);

enable_if 的主要作用就是当某个 condition 成立时,enable_if可以提供某种类型。enable_if在标准库中通过结构体模板实现的,声明如下:

template<bool Cond, class T = void> struct enable_if;

英文解释如下:

Enable type if the condition is met.
    The type T is enabled as member type enable_if::type if Cond is true. Otherwise, enable_if::type is not defined.

但是当 condition 不满足的时候,enable_if<>::type 就是未定义的,当用到模板相关的场景时,只会 instantiate fail,并不会编译错误,这时很重要的一点。为了理解 std::enable_if<> 的实现,我们先来了解一下 SFINAE。
SFINAE

SFINAE 是C++ 的一种语言属性,具体内容就是”从一组重载函数中删除模板实例化无效的函数”。

Prune functions that do not yield valid template instantiations from a set of overload functions.

SFINAE 的的全称是 Substitution Failure Is Not An Error。

SFINAE 应用最为广泛的场景是C++中的 std::enable_if,这里有完整的英文描述:

In the process of template argument deduction, a C++ compiler attempts to instantiate signatures of a number of candidate overloaded functions to make sure that exactly one overloaded function is available as a perfect match for a given function call.

从上面的描述中我们可以看到,在对一个函数调用进行模板推导时,编译器会尝试推导所有的候选函数(重载函数,模板,但是普通函数的优先级要高),以确保得到一个最完美的匹配。

If an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error.
    As long as there is one and only one function to which the call can be dispatched, the compiler issues no errors.

也就是说在推导的过程中,如果出现了无效的模板参数,则会将该候选函数从重载决议集合中删除,只要最终得到了一个 perfect match ,编译就不会报错。

如下代码所示:

long multiply(int i, int j) { return i * j; }   #1

template <class T>
typename T::multiplication_result multiply(T t1, T t2)
{
    return t1 * t2;
}

int main(void)
{
    multiply(4, 5); //最佳匹配为int multiply(int,int),T为int为最佳;但是int没有multiplication_result成员,所以,使用#1,
}

main 函数调用 multiply 会使编译器会尽可能去匹配所有候选函数,虽然第一个 multiply 函数明显是较优的匹配,但是为了得到一个最精确的匹配,编译器依然会尝试去匹配剩下的候选函数,此时就会去推导 第二个multiply 函数,中间在参数推导的过程中出现了一个无效的类型 int::multiplication_result ,但是因为 SFINAE 原则并不会报错。
std::enable_if<> 的实现

前面我们在介绍 std::enable_if 的时候提到,如果 condition 不满足的话,会生成一个无效的类型,此处由于 SFINAE 机制的存在,只要 call 存在一个匹配的话,就不会报错(只是简单的丢弃该函数)。

std::enable_if<>的实现机制如下代码所示:

template<bool Cond, typename T = void> struct enable_if {};

template<typename T> struct enable_if<true, T> { typedef T type; };

从上面的代码可以看到,在 condition 为真的时候,由于偏特化机制,第二个结构体模板明显是一个更好的匹配,所以 std::enable_if<>::type 就是有效的。当 condition 为假的时候,只有第一个结构体模板能够匹配,所以 std::enable_if<>::type 是无效的,会被丢弃。

Note: 下面是Visual Studio 2013的实现:

// TEMPLATE CLASS enable_if
template<bool _Test,
    class _Ty = void>
    struct enable_if
    {   // type is undefined for assumed !_Test
    };

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

std::enable_if<> 使用及使用

std::enable_if<> 的使用原型如下所示:

template <bool Cond, class T = void> struct enable_if;

1

Cond, A compile-time constant of type bool
    T, A type.

使用 enable_if 的时候,对参数有这两方面的限制。
member type     definition
type     T (defined only if Cond is true)

该例子来自于 这里:

// enable_if example: two ways of using enable_if
#include <iostream>
#include <type_traits>

// 1. the return type (bool) is only valid if T is an integral type:
template <class T>
typename std::enable_if<std::is_integral<T>::value,bool>::type
  is_odd (T i) {return bool(i%2);}

// 2. the second template argument is only valid if T is an integral type:
template < class T,
           class = typename std::enable_if<std::is_integral<T>::value>::type>
bool is_even (T i) {return !bool(i%2);}

int main() {

short int i = 1;    // code does not compile if type of i is not integral;如果 inr为非整型,代码不会编译;  std::cout <<     std::boolalpha;
  std::cout << "i is odd: " << is_odd(i) << std::endl;
  std::cout << "i is even: " << is_even(i) << std::endl;

return 0;
}

C++11 enable_if 详解相关推荐

  1. RAD Studio 11.2详解其务实改进(Delphi C++ Builder)-Alexandria

    RAD Studio 11.2详解其务实改进(Delphi & C++ Builder)-Alexandria 目录 RAD Studio 11.2详解其务实改进(Delphi & C ...

  2. 我的世界connect指令php,我的世界1.11指令大全 1.11指令详解

    我的世界1.11指令大全 1.11指令详解.那下面给大家分享的则是1.11版本中的一些指令哦~那不知道我的世界1.11版本有哪些指令的玩家不妨进来看看下面的介绍吧! 游戏园我的世界官方群:325049 ...

  3. 【小白学PyTorch】11.MobileNet详解及PyTorch实现

    <<小白学PyTorch>> 小白学PyTorch | 10 pytorch常见运算详解 小白学PyTorch | 9 tensor数据结构与存储结构 小白学PyTorch | ...

  4. 黑客攻击我们的11步详解及防御建议

    安全公司Aorato的一项新研究显示,个人可识别信息(PII)和信用卡及借记卡数据在今年年初的Target数据泄露实践中遭到大规模偷窃后,该公司的PCI合规新计划已经大幅降低了损害的范围. 利用所有可 ...

  5. 802.11 wireless 详解

    wireless 是个广义的概念 这个 空气波形传播写以在1991年时就标准化了在后来一步步补充完善, 它包含短波传输 bluetooth nfc ,中场波wlan 和 zigbee . 下来我们讲一 ...

  6. Linux 内核0.11 系统调用详解(下)

    备注:上讲中,博猪讲到了操作系统是如何让用户程序调用系统函数的,这讲继续接上讲的话题,从一个系统内核系统函数创建的小实验来学习系统内核具体做了些什么.理清下系统调用的整体过程. 实验:在Linux 0 ...

  7. 极力推荐自由飞鸽的电子书《linux 0.11内核详解》,我传至纳米盘,也可到oldlinux.org 去下载

    2007修订版: http://d.namipan.com/d/6834dabccb51dcfd6112ce54e47c87aa5f7fdb1ec7e96400 2002经典版: http://d.n ...

  8. 4.6 W 字总结!Java 11—Java 17特性详解

    作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...

  9. ROS(11)move_base详解

    11. move_base详解 11.1. move_base配置参数解读 参考链接:https://blog.csdn.net/banzhuan133/article/details/9023925 ...

  10. 【小白学PyTorch】扩展之Tensorflow2.0 | 21 Keras的API详解(下)池化、Normalization

    <<小白学PyTorch>> 扩展之Tensorflow2.0 | 21 Keras的API详解(上)卷积.激活.初始化.正则 扩展之Tensorflow2.0 | 20 TF ...

最新文章

  1. 【AI学习篇】实战深度学习(3):深度学习的数据表示
  2. @echo off是什么意思_为什么执行自己的程序要在前面加./
  3. 被问到了!为什么一定要使用分布式,内行啊
  4. 位同步技术中的比相法
  5. 前端学习(2967):表单验证
  6. 关于hive和spark日志问题
  7. Linux内核数据结构之哈希表
  8. open SUSE 查看本机ip地址
  9. zencart模板制作步骤详解
  10. React Fullpage
  11. 做自适应网站专业乐云seo_广州网站设计【乐云seo】
  12. Hessian矩阵以及在图像中的应用
  13. 深入理解C++的动态绑定和静态绑定 1
  14. Linux无法显示ip的解决办法
  15. 基于ASP.NET大学生校园招聘网站的设计与开发
  16. Linux下copy命令,并重命名
  17. ctf-misc-150分登机牌(150分
  18. 用卡西欧计算器玩三国杀。神一样的高中生
  19. 知识图谱库汇总!——教育领域能够直接应用的知识图谱
  20. UR机械臂学习(9):加入robotiq力传感器

热门文章

  1. 计算机ata考试教案,ATA办公软件考级教案(四).docx
  2. STC89C52RC单片机额外篇 | 04 - 认识头文件<intrins.h>与_nop_函数
  3. dlna和miracast可以共存吗_电脑如何投屏到电视?除了Miracast还有DLNA
  4. ROS中一个关于时间的函数
  5. 遮天 | 实战绕过卡巴斯基、Defender上线CS和MSF及动态命令执行...
  6. 2022年R1快开门式压力容器操作理论题库及在线模拟考试
  7. 如何从海量用户发布的内容中挖掘出各城市时下的最热话题
  8. ACP敏捷9.敏捷应用场景
  9. 天道酬勤系列之Redis 事务的介绍与实例使用
  10. 刚构桥的优缺点_桥的类型以及适用条件,优缺点