SFINAE 与 type_traits

SFINAE

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

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

type_traits

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

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

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

template <class _Ty, _Ty _Val>
struct integral_constant { // convenient template for integral constant types
static constexpr _Ty value = _Val; using value_type = _Ty;
using type = integral_constant; constexpr operator value_type() const noexcept { // return stored value
return (value);
}
constexpr value_type operator()() const noexcept { // return stored value
return (value);
}
};

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

// ALIAS TEMPLATE bool_constant
template <bool _Val> using bool_constant = integral_constant<bool, _Val>; using true_type = bool_constant<true>;
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

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

// STRUCT TEMPLATE 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
using type = _Ty;
}; template <bool _Test, class _Ty = void>
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

// STRUCT TEMPLATE is_same
template <class _Ty1, class _Ty2>
struct is_same
: false_type { // determine whether _Ty1 and _Ty2 are the same type
}; template <class _Ty1>
struct is_same<_Ty1, _Ty1>
: true_type { // determine whether _Ty1 and _Ty2 are the same type
}; template <class _Ty, class _Uty>
constexpr bool is_same_v = is_same<_Ty, _Uty>::value;

remove_const

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

// STRUCT TEMPLATE remove_const
template <class _Ty> struct remove_const { // remove top level const qualifier
using type = _Ty;
}; template <class _Ty>
struct remove_const<const _Ty> { // remove top level const qualifier
using type = _Ty;
}; template <class _Ty> using remove_const_t = typename remove_const<_Ty>::type;

remove_reference

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

// STRUCT TEMPLATE remove_reference
template <class _Ty> struct remove_reference { // remove reference
using type = _Ty;
}; template <class _Ty> struct remove_reference<_Ty &> { // remove reference
using type = _Ty;
}; template <class _Ty>
struct remove_reference<_Ty &&> { // remove rvalue reference
using type = _Ty;
}; template <class _Ty>
using remove_reference_t = typename remove_reference<_Ty>::type;

其他需要编译器外挂的 traits

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

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

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

__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. Eclipse 导入 Tomcat 源码

    我的环境:Win10,Eclipse 4.8.0 Photon,JDK 10.0.2   1.下载Tomcat源码 我下载的是:apache-tomcat-9.0.12-src.zip 下载地址:ht ...

  2. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 按钮:内嵌下拉菜单的按钮组

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 按钮:自适应大小的按钮组

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. Vue中 onmouseenter,onmouseleave,onmouseover,onmouseout的区别

    今天在学Vue视频的时候,提到了这四个触发事件,我就想做下笔记: 1.onmouseenter和onmouseleave是一组:当鼠标进入指定区域的时候触发,但是不支持冒泡,进入或者离开子组件都不触发 ...

  5. (译)Calculus on Computational Graphs: Backpropagation

    Posted on August 31, 2015 Introduction Backpropagation is the key algorithm that makes training deep ...

  6. Kubernetes 各版本镜像列表

    以下镜像列表由 kubeadm v1.11.1 导出,若使用预下载镜像离线部署的方式部署,请使用 kubeadm v1.11.1 版本 导出各版本镜像列表: kubeadm config images ...

  7. Day5-T1

    原题目 小月言要过四岁生日了,她的妈妈为她准备了n根火腿,她想将这些火腿均分给m位小朋友,所以她可能需要切火腿.为了省事,小月言想切最少的刀数,使这n根火腿分成均等的m份.请问最少要切几刀? 第一行一 ...

  8. Day5-T2

    原题目 根据社会学研究表明,人们都喜欢和自己身高相近的人做朋友. 现在有 N 名身高各不相同的同学依次走进教室. 调查人员想预测每个人在走入教室的瞬间最想和 已经在教室的哪个人做朋友.当有两名同学和这 ...

  9. 挖洞经验 | 绕过WAF限制利用php:方法实现OOB-XXE漏洞利用

    几个星期以前,作者在某个OOB-XXE漏洞测试中遇到过这样一种场景:目标应用后端系统WAF防火墙阻挡了包含DNS解析在内的所有出站请求(Outgoing Request),但最终,通过利用php:// ...

  10. SpringIOC初始化过程源码跟踪及学习

    Spring版本 4.3.2,ssm框架 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 web.xml <!--配置获取项目的根路径,java类中使用System.getProperty ...