SFINAE 与 type_traits

SFINAE

替换失败不是错误 (Substitution Failure Is Not An Error),此特性被用于模板元编程。

在函数模板的重载决议中应用此规则,当将模板形参替换为显式指定的类型或推导的类型失败时,从重载集中丢弃这个特化,而非导致编译失败

type_traits

类型特性 定义一个编译时基于模板的结构,以查询或修改类型的属性,是一种类型萃取技术。

type_traits 在 C++ 中是基于 SFINAE 实现的,通过模板的偏特化来查询或者修改类型的属性,无运行时开销。

其核心是整数常量模板 integral_constant,MSVC 的实现如下:

  1. template <class _Ty, _Ty _Val>
  2. struct integral_constant { // convenient template for integral constant types
  3. static constexpr _Ty value = _Val;
  4. using value_type = _Ty;
  5. using type = integral_constant;
  6. constexpr operator value_type() const noexcept { // return stored value
  7. return (value);
  8. }
  9. constexpr value_type operator()() const noexcept { // return stored value
  10. return (value);
  11. }
  12. };

其实平平无奇,保存了类模板的类型和值而已,没有什么特殊的地方,现在将这个模板特化为bool类型

  1. // ALIAS TEMPLATE bool_constant
  2. template <bool _Val> using bool_constant = integral_constant<bool, _Val>;
  3. using true_type = bool_constant<true>;
  4. using false_type = bool_constant<false>;

bool_constant 的实参只能是 bool 类型, true_type 的 integral_constant::value 是true,false_type 的 value 是 false,构建 traits 的基础已经完成。

常见的几种 traits 的 SFINAE 应用

像 std::enable_if, is_same, remove_const, remove_reference 等这些是最常用的 traits,STL的代码中这些到处可见。

enable_if

根据编译期布尔常量隐藏一个函数重载或模板特化。

  1. // STRUCT TEMPLATE enable_if
  2. template <bool _Test, class _Ty = void>
  3. struct enable_if { // type is undefined for assumed !_Test
  4. };
  5. template <class _Ty> struct enable_if<true, _Ty> { // type is _Ty for _Test
  6. using type = _Ty;
  7. };
  8. template <bool _Test, class _Ty = void>
  9. using enable_if_t = typename enable_if<_Test, _Ty>::type;

若 B 为 _Test ,则 std::enable_if 拥有等同于 T 的公开成员 typedef type (第二个模板实参),否则,无该成员 typedef。

is_same

检测两个参数类型是否相同,如果相同特供 value 为 true,否则为false。实现简单,相同参数的继承 true_type, 不同参数的继承 false_type

  1. // STRUCT TEMPLATE is_same
  2. template <class _Ty1, class _Ty2>
  3. struct is_same
  4. : false_type { // determine whether _Ty1 and _Ty2 are the same type
  5. };
  6. template <class _Ty1>
  7. struct is_same<_Ty1, _Ty1>
  8. : true_type { // determine whether _Ty1 and _Ty2 are the same type
  9. };
  10. template <class _Ty, class _Uty>
  11. constexpr bool is_same_v = is_same<_Ty, _Uty>::value;

remove_const

控制给定类型限定符是否存在。volatile 同理。

  1. // STRUCT TEMPLATE remove_const
  2. template <class _Ty> struct remove_const { // remove top level const qualifier
  3. using type = _Ty;
  4. };
  5. template <class _Ty>
  6. struct remove_const<const _Ty> { // remove top level const qualifier
  7. using type = _Ty;
  8. };
  9. template <class _Ty> using remove_const_t = typename remove_const<_Ty>::type;

remove_reference

从给定类型移除引用,add_*value_reference 实现类似。

  1. // STRUCT TEMPLATE remove_reference
  2. template <class _Ty> struct remove_reference { // remove reference
  3. using type = _Ty;
  4. };
  5. template <class _Ty> struct remove_reference<_Ty &> { // remove reference
  6. using type = _Ty;
  7. };
  8. template <class _Ty>
  9. struct remove_reference<_Ty &&> { // remove rvalue reference
  10. using type = _Ty;
  11. };
  12. template <class _Ty>
  13. using remove_reference_t = typename remove_reference<_Ty>::type;

其他需要编译器外挂的 traits

像上面这些都是可以通过库来实现的 traits,这种一般也比较简单的。其他的和类 枚举 虚函数 这些相关一般都要通过内建支持。

最先想到的就是 is_trivial,这种要通过库来实现就不可能了:

  1. 没有虚函数或虚基类;
  2. 由C++编译器提供默认的特殊成员函数(默认的构造函数、拷贝构造函数、移动构造函数、赋值运算符、移动赋值运算符和析构函数),并且最少有一个未弃置;
  3. 数据成员同样需要满足条件 12
  1. // STRUCT TEMPLATE is_trivial
  2. template <class _Ty>
  3. struct is_trivial
  4. : bool_constant<__is_trivial(_Ty)> { // determine whether _Ty is trivial
  5. };

__is_trivial 就是编译器的外挂了,traits 的这种实现一直秉持着能够库实现,绝不编译器去做的原则。

参考

  1. SFINAE, cppreference.com.
  2. std::is_trivial, cppreference.com.

SFINAE 与 type_traits的更多相关文章

  1. c++11——type_traits 类型萃取

    一. c++ traits traits是c++模板编程中使用的一种技术,主要功能:     把功能相同而参数不同的函数抽象出来,通过traits将不同的参数的相同属性提取出来,在函数中利用这些用tr ...

  2. C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE

    本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...

  3. C++ SFINAE

    1. 什么是SFINAE 在C++中有很多的编程技巧(Trick), SFINAE就是其中一种, 他的全义可以翻译为”匹配失败并不是一个错误(Substitution failure is not a ...

  4. C++ type_traits 原理

    一.简单介绍 (1).type_traits 类型萃取,C++11中已结成为了一个核心模块. (2).标准库包括helper classes .type traits.type transformat ...

  5. 第17课 类型萃取(1)_基本的type_traits

    1. type_traits类型萃取 (1)type_traits通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异.在程序设计中可以使用这些tra ...

  6. MSVC 12: compiler error in boost/type_traits/common_type.hpp

    来自: https://svn.boost.org/trac10/ticket/11885 MSVC 12: compiler error in boost/type_traits/common_ty ...

  7. SFINAE简单实例

    SFINAE(Substitution failure is not an error),是C++11以来推出的一个重要概念,这里,只是简单举一个例子,可能会有人需要. // 添加 scalar nu ...

  8. type_traits.h

    type_traits.h // Filename: type_traits.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: ht ...

  9. STL之__ type_traits

    __type_traits:双底线是说明这是SGI STL内部使用的东西,不在STL标准范围之内.iterator_traits负责萃取迭代器(iterator)的特性.而__type_traits则 ...

随机推荐

  1. 「PA2014」Kuglarz

    传送门 memset0好评 解题思路 其实这是一道图论题 不难发现,如果知道了 \(\sum1...i\) 和 \(\sum1...j\) 的奇偶性,那么就可以得知 \(\sum i+1...j\) ...

  2. Myeclipse 安装时候android adt, android sdk常见问题

    离线版adt安装  可以随意百度adt下载 安装时候注意断网模式,否则会连接到服务器耗费很长时间:如果安装报错,可能是adt与Myeclipse版本不匹配,如我用的是Myeclipse8.6,安装AD ...

  3. 禁用UpdateOrchestrator重新启动任务

    LTSC2019 联网下载更新后,总是用户不使用电脑的时候重启更新系统. 搜索发现是计划任务中\Microsoft\Windows\UpdateOrachestrator重新任务的导致的. 查看这个任 ...

  4. python如何输出矩阵的行数与列数?

    Python如何输出矩阵的行数与列数? 对于pyhton里面所导入或者定义的矩阵或者表格数据,想要获得矩阵的行数和列数有以下方法: 1.利用shape函数输出矩阵的行和列 x.shape函数可以输出一 ...

  5. 攻防世界web新手练习区(2)

    弱认证:http://111.198.29.45:43769/ 打开是这个页面: 用户名输入1,密码输入2,试试看.会提示你用户名为admin.接下来用burp对密码进行爆破,发现弱口令0123456 ...

  6. 2018--Linux命令总结整理复习版

    一.ls命令: 用来显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. -a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影 ...

  7. 解决Google浏览器不能打开kubernetes dashboard方法【转】

    在这片文章中,我将展示如何在Google Chrome上打开kubernetes dashboard.本文不叙述如何安装搭建docker和kubernetes,有关详情请上网查阅! 很多小伙伴们在自己 ...

  8. hue中访问hdfs报错

    在hue中访问hdfs报错: Cannot access: /. Note: you are a Hue admin but not a HDFS superuser, "hdfs" ...

  9. input type="submit" 和"button"有什么区别

    HTML中<input type="submit" /> 和 <input type="button" /> 主要从元素定义类型.点击触 ...

  10. 012-PHP创建一个多维数组

    <?php $Cities = array( //二维数组array() "华北地区"=>array( "北京市", "天津市" ...