SFINAE 与 type_traits
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,这种要通过库来实现就不可能了:
- 没有虚函数或虚基类;
- 由C++编译器提供默认的特殊成员函数(默认的构造函数、拷贝构造函数、移动构造函数、赋值运算符、移动赋值运算符和析构函数),并且最少有一个未弃置;
- 数据成员同样需要满足条件 1 和 2。
// STRUCT TEMPLATE is_trivial
template <class _Ty>
struct is_trivial
: bool_constant<__is_trivial(_Ty)> { // determine whether _Ty is trivial
};
__is_trivial 就是编译器的外挂了,traits 的这种实现一直秉持着能够库实现,绝不编译器去做的原则。
参考
- SFINAE, cppreference.com.
- std::is_trivial, cppreference.com.
SFINAE 与 type_traits的更多相关文章
- c++11——type_traits 类型萃取
一. c++ traits traits是c++模板编程中使用的一种技术,主要功能: 把功能相同而参数不同的函数抽象出来,通过traits将不同的参数的相同属性提取出来,在函数中利用这些用tr ...
- C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE
本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...
- C++ SFINAE
1. 什么是SFINAE 在C++中有很多的编程技巧(Trick), SFINAE就是其中一种, 他的全义可以翻译为”匹配失败并不是一个错误(Substitution failure is not a ...
- C++ type_traits 原理
一.简单介绍 (1).type_traits 类型萃取,C++11中已结成为了一个核心模块. (2).标准库包括helper classes .type traits.type transformat ...
- 第17课 类型萃取(1)_基本的type_traits
1. type_traits类型萃取 (1)type_traits通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异.在程序设计中可以使用这些tra ...
- 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 ...
- SFINAE简单实例
SFINAE(Substitution failure is not an error),是C++11以来推出的一个重要概念,这里,只是简单举一个例子,可能会有人需要. // 添加 scalar nu ...
- type_traits.h
type_traits.h // Filename: type_traits.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: ht ...
- STL之__ type_traits
__type_traits:双底线是说明这是SGI STL内部使用的东西,不在STL标准范围之内.iterator_traits负责萃取迭代器(iterator)的特性.而__type_traits则 ...
随机推荐
- 「NOIP2011」观光公交
传送门 Luogu 解题思路 有点麻烦,幸好 \(O(n^2)\) 能过... 贪心地想一想,我们如果要用加速器,肯定是要选择车上人数最多的时段加速. 但是我们就会面临这样的情况: 加速了,带来了增益 ...
- 「LuoguP3979」遥远的国度
传送门 Luogu 解题思路 带换根操作的树剖. 换根只会影响更新或查询子树信息的操作. 我们始终保持初始的根不变,然后只要分类讨论一下: 假设当前被查询的节点是 \(u\) 如果 \(u\) 就是根 ...
- java对象转换String类型的三种方法
在很多情况下我们都需要将一个对象转换为String类型.一般来说有三种方法可以实现:Object.toString().(String)Object.String.valueOf(Object).下面 ...
- partialview 用法
using MvcApplication1.Models; @model MvcApplication1.Models.UserInfoModel @{ ViewBag.Title = &q ...
- zabbix proxy配置实战案例
zabbix proxy配置实战案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.zabbix proxy概述 上一篇博客我们分享了zabbix agent有两种工作模式,即 ...
- 【LeetCode】三角形最小路径和
[问题]给定一个三角形,找出自顶向下的最小路径和.每一步只能移动到下一行中相邻的结点上.例如,给定三角形: [ [], [,], [,,], [,,,] ] 自顶向下的最小路径和为 (即, + + + ...
- docker学习笔记-01:docker基本原理
一.docker原理 1.什么是docker:解决了运行环境和配置问题的容器,方便做持续集成并有助于整体发布的容器虚拟化技术. 2.虚拟机的缺点:(1)资源占用多:(2)冗余步骤多:(3)启动慢,分钟 ...
- vue table已选列数据
vue Table@on-selection-change="test" 已选中项数据 test(selection){} <Table :data="tableD ...
- Java笔记--反射机制
1.Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法. 2.Java反射机制提供 ...
- java学习之IO流(学习之旅,一)
个人在学习IO流的时候看到如下所示java 流类图结构的时候,我的感想是,这么多··处于蒙的状态. Java流类图结构 这么多,没有分类不好学,那我们就慢慢一口一口的吃,这样每天学习一点就好了,其实很 ...