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. 最新获取 QQ头像 和 昵称接口

    网上找来的测试可用... 获取QQ头像 http://q2.qlogo.cn/headimg_dl?bs=QQ号&dst_uin=QQ号&dst_uin=QQ号&;dst_ui ...

  2. (转)浅谈 Linux 内核无线子系统

    前言 Linux 内核是如何实现无线网络接口呢?数据包是通过怎样的方式被发送和接收呢? 刚开始工作接触 Linux 无线网络时,我曾迷失在浩瀚的基础代码中,寻找具有介绍性的材料来回答如上面提到的那些高 ...

  3. 使用 Doxygen 生成文档 (以FFmpeg 4.1.1 为例)

    背景 在查找 ffmpeg 文档的时候,发现其文档是根据 Doxygen 生成的. 为了学习方便,这里以 生成 ffmpeg 4.1 文档 为例. 注:为了兼顾 arm 与 host ,本人选择了同时 ...

  4. java 十大经典排序算法

    十大排序算法可以说是每个程序员都必须得掌握的了,花了一天的时间把代码实现且整理了一下,为了方便大家学习,我把它整理成一篇文章,每种算法会有简单的算法思想描述,为了方便大家理解,我还找来了动图演示:这还 ...

  5. day06-Python运维开发基础(字符串格式化与相关的函数、列表相关的操作)

    1. 字符串相关的操作与格式化 # ### 字符串相关操作 # (1)字符串的拼接 + var1 = "亲爱的," var2 = "男孩" res = var1 ...

  6. eshop5-maven 安装

    1. Maven 安装 2.下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.0.5/binaries/ 3. 通过ta ...

  7. JSON数组序列化C#方法

    /// <summary> /// dataTable转换成Json格式 JSON对应关系 三层数组 /// </summary> /// <param name=&qu ...

  8. 记一次Win上MySQL乱码问题

    Win上MySQL乱码问题 笔记本上的数据库总会时不时的乱码(或者是一直乱码我没注意到?),在谷歌上试了几次错才正确解决,在此记录一下. 在MySQL数据库存储目录找到my.ini,在相应的标签下分别 ...

  9. 动手实验01-----vCenter 微软AD认证配置与用户授权

    环境说明: AD域->   centaline.net 阅读目录: 1. 配置与AD认证源 2.权限角色 1. 配置与AD认证源 登陆vCenter后,在 系统管理 -> 配置 -> ...

  10. 又一个无效的列类型错误Error setting null for parameter #7 with JdbcType NULL . Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. Cause: java.sql.SQLExcept

    在更新数据时候出现的错误 更新代码如下: <update id="modify" parameterType="Standard"> update ...