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. IOS TableView 用法

    1.在视图上创建TableView( 拖控件),为ViewController创建UITableView属性(链接至TableView)和NSArray属性(存储数据) ViewController. ...

  2. leetcode813 Largest Sum of Averages

    """ We partition a row of numbers A into at most K adjacent (non-empty) groups, then ...

  3. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:"text-muted" 类的文本样式

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

  4. springboot项目启动报错 Failed to configure a DataSource: 'url' attribute is not specified and no embedde

    参考:https://blog.csdn.net/Coyotess/article/details/80637837

  5. grep -o -E

    sed 命令可以很好的进行行匹配,但从某一行中精确匹配某些内容,则使用 grep 命令并辅以 -o 和 -E 选项可达到此目的.其中 -o 表示“only-matching”,即“仅匹配”之意.光用它 ...

  6. python isdigit()函数

    isdigit() 函数是作用于字符串的,用来判断字符串是否全部由数字组成. x = '123456' y = 'iloveyou123' print(x.isdigit(),y.isdigit()) ...

  7. 微信小程序—页面跳转

    问题: 实现页面跳转:index页面通过按钮跳转到next页面 方法: 1.页面index.wxml增加一个按钮 // index.wxml <button bindtap="jump ...

  8. tp3.2 自带的文件上传及生成缩略图功能

    public function upload_file($file_name,$width,$height) { //检查图片尺寸是否合法 $image_size = getimagesize($_F ...

  9. 019、Java中定义字符

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  10. 003.Oracle数据库 , 查询日期格式格式化

    /*日期格式转换*/ SELECT TO_CHAR( OCCUR_DATE, 'yyyy/mm/dd hh24:mi:ss' ) FROM LM_FAULT WHERE ( ( OCCUR_DATE ...