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. django 自定义模版过滤器

    自定义的模版过滤器必须要放在app中,并且该app必须在INSTALLED_APPS中进行安装.然后再在这个app下面创建一个python包叫做templatetags(这个名字是固定的,不能随意更改 ...

  2. Lamda简单使用

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. arm linux 移植 udhcp 与 使用

    背景 在一些网络环境下,需要静态IP不够现实,需要使用DHCP进行自动获取IP地址. udhcpc是一个面向嵌入式系统的非常小的DHCP客户端,字母的缩写微μ- DHCP -客户端client(μDH ...

  4. kali 中文乱码解决方法

    本文转自https://www.cnblogs.com/sym945/p/11943842.html#4449966 1.更换阿里源 vim /etc/apt/sources.list,编辑源之后,a ...

  5. 如果shell到win上出现乱码怎么办

    如果shell到win上出现这样的乱码怎么办? 如果出现了乱码,不慌一条命令搞定它!!! chcp 65001

  6. iOS 枚举ENUM和OPTIONS的区别

  7. 浅谈JVM线程调度机制及主要策略

    在之前有说过线程,应该都知道,所谓线程就是进程中的一个子任务,一个进程有多个线程.今天的话主要就是谈一谈JVM线程调度机制.我们结合线程来说,当我们在做多线程的案例时,如一个经典案例,火车站卖票. * ...

  8. prepareBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  9. HDU1054-Strategic Game

    Strategic Game Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. https://blog.csdn.net/yyoinge/article/details/81557604

    https://blog.csdn.net/yyoinge/article/details/81557604 http://www.mamicode.com/info-detail-2346464.h ...