C++11的std::is_same和std::decay源码解析

  • 1、源码准备
  • 2、使用方法
    • 2.1、std::is_same使用方法
    • 2.2、std::decay使用方法
    • 2.3、std::is_same和std::decay配合使用
  • 3、源码解析
    • 3.1、std::is_same源码解析
    • 3.2、std::decay源码解析
  • 4、总结

1、源码准备

本文是基于gcc-4.9.0的源代码进行分析,std::is_same和std::decay是C++11才加入标准的,所以低版本的gcc源码是没有这个的,建议选择4.9.0或更新的版本去学习,不同版本的gcc源码差异应该不小,但是原理和设计思想的一样的,下面给出源码下载地址
http://ftp.gnu.org/gnu/gcc

2、使用方法

std::is_samestd::decay是C++11新增的两个模板类,功能分别是类型判断和类型朽化。

2.1、std::is_same使用方法

首先通过一个例子看一下std::is_same的使用方法:

#include <iostream>
#include <type_traits>
#include <stdint.h>int main(int argc, char* argv[])
{std::cout << "第一组,类型的写法完全相同" << std::endl;std::cout << std::is_same<int, int>::value << std::endl;         // truestd::cout << std::is_same<double, double>::value << std::endl;   // truestd::cout << std::is_same<int32_t, int32_t>::value << std::endl; // truestd::cout << std::is_same<int64_t, int64_t>::value << std::endl; // truestd::cout << std::endl << "第二组,类型相同,但是写法不同(typedef重命名了)" << std::endl;std::cout << std::is_same<short, int16_t>::value << std::endl;   // truestd::cout << std::is_same<int, int32_t>::value << std::endl;     // truestd::cout << std::is_same<long, int64_t>::value << std::endl;    // truestd::cout << std::is_same<unsigned int, uint32_t>::value << std::endl; // truestd::cout << std::endl << "第三组,类型不同" << std::endl;std::cout << std::is_same<char, int>::value << std::endl;        // falsestd::cout << std::is_same<double, float>::value << std::endl;    // falsestd::cout << std::is_same<float, long>::value << std::endl;      // falsestd::cout << std::is_same<double, char>::value << std::endl;     // falsestd::cout << std::endl << "第四组,类型其实是一样的,只是省略写法而已" << std::endl;std::cout << std::is_same<char, signed char>::value << std::endl;   // falsestd::cout << std::is_same<char, unsigned char>::value << std::endl; // falsestd::cout << std::is_same<short, signed short>::value << std::endl; // truestd::cout << std::is_same<int, signed int>::value << std::endl;     // truestd::cout << std::endl << "第五组,类型不同" << std::endl;std::cout << std::is_same<char*, char[]>::value << std::endl;           // falsestd::cout << std::is_same<const char, char>::value << std::endl;        // falsestd::cout << std::is_same<const char&, const char>::value << std::endl; // falsestd::cout << std::is_same<const int&, int>::value << std::endl;         // false
}

上面的结果中,前三组应该是没啥歧义的,因为std::is_same是可以识别出被typedefdefine重命名的类型的原始类型的。第四组就有点意思了,除了前面两个以外都是true,说明std::is_same是可以判断出signedsigned+类型是相同的。第五组的话也没什么好说的,类型确实不同。

这里解释一下,从上面的代码中看得出来,char既不是unsigned char也不是signed charchar的表达数值范围可能等同于signed char,也可能等同于unsigned char,这取决于编译器,一般是等同于signed char,但这仅仅是范围等同,就像32位机上intlong的数值范围是一样的,但并不是同一个类型。

2.2、std::decay使用方法

std::decay人如其名,就是朽化的意思,主要是对一个类型进行朽化处理,说白一点就是将类型的一些属性比如constvolatile&(引用)等消除掉,需要注意指针是消不掉。首先通过一个例子看一下std::decay的使用方法:

#include <iostream>
#include <type_traits>
#include <stdint.h>int main(int argc, char* argv[])
{const int a = 10l;// 报错,const修饰的不能改变//a = 10;std::decay<const int>::type b = 101;// 可以修改b = 10;
}

从上面的例子可以看出经过std::decay处理之后,const intconst属性就没了,这就是std::decay的一个典型用法

2.3、std::is_same和std::decay配合使用

代码如下,可以看到,经过std::decay朽化之后,原本使用std::is_same判断不相同的类型也变得相同了,这里需要注意的是直接使用std::is_same去判断char*char[],显示是不相同的,但是经过朽化之后这两个就变得相同了,这个情况原理在后面会讲。

#include <iostream>
#include <type_traits>
#include <stdint.h>int main(int argc, char* argv[])
{std::cout << std::is_same<std::decay<int>::type, std::decay<int>::type>::value << std::endl;       // truestd::cout << std::is_same<std::decay<const int>::type, std::decay<int>::type>::value << std::endl; // truestd::cout << std::is_same<std::decay<int&>::type, std::decay<int>::type>::value << std::endl;      // truestd::cout << std::is_same<std::decay<const int>::type, std::decay<const volatile int>::type>::value << std::endl; // truestd::cout << std::is_same<std::decay<const volatile int&>::type, std::decay<int>::type>::value << std::endl; // truestd::cout << std::is_same<std::decay<char*>::type, std::decay<char[]>::type>::value << std::endl; // true
}

3、源码解析

3.1、std::is_same源码解析

std::is_same位于libstdc++-v3\include\std\type_traits

template<typename, typename>
struct is_same : public false_type { };template<typename _Tp>
struct is_same<_Tp, _Tp> : public true_type { };

可以看到,代码非常简单,第一个是泛化形式,第二个是偏特化形式,当两个类型相同时,调用的是第二个,而第二个继承的是true_type,所以此时is_same<_Tp, _Tp>::value的值就是true;相反的,当两个类型不同时,调用第一个,此时is_same<_Tp, _Tp>::value的值就是false

3.2、std::decay源码解析

std::decay位于libstdc++-v3\include\std\type_traits

template<typename _Tp>
class decay
{ typedef typename remove_reference<_Tp>::type __remove_type;public:typedef typename __decay_selector<__remove_type>::__type type;
};

可以看到,首先使用了std::remove_reference_Tp的引用属性去除了,关于std::remove_reference的内容之前在这篇文章《C++11的右值引用、移动语义(std::move)和完美转发(std::forward)详解》中有讲过,这里就不赘述了,大家可以自己去看一下。然后使用了std::__decay_selector,下面看一下std::__decay_selector的源码

template<typename _Up, bool _IsArray = is_array<_Up>::value,bool _IsFunction = is_function<_Up>::value>
struct __decay_selector;template<typename _Up>
struct __decay_selector<_Up, false, false>
{ typedef typename remove_cv<_Up>::type __type; };template<typename _Up>
struct __decay_selector<_Up, true, false>
{ typedef typename remove_extent<_Up>::type* __type; };template<typename _Up>
struct __decay_selector<_Up, false, true>
{ typedef typename add_pointer<_Up>::type __type; };

可以看到共有三种偏特化形式:

  1. 第一种就是当_Up既不是数组形式也不是可调用实体形式时匹配,使用了std::remove_cv去除了_Upconstvolatile属性。关于std::remove_cv可以看一下这篇文章《C++11的std::ref、std::cref源码解析》,里面有详细介绍
  2. 第二种就是当_Up是数组时匹配,使用了std::remove_cv去除了_Up的数组属性,只留下个数组名指针,这就是为什么前面使用std::decay之后char*char[]会显示相同的原因了。
template<typename _Tp>
struct remove_extent
{ typedef _Tp     type; };template<typename _Tp, std::size_t _Size>
struct remove_extent<_Tp[_Size]>
{ typedef _Tp     type; };template<typename _Tp>
struct remove_extent<_Tp[]>
{ typedef _Tp     type; };
  1. 第三种就是当_Up是可调用实体时匹配,使用了std::add_pointer去除了_Up的引用属性,代码与前面的那些原理是一样的,这里就不细讲了,大家可以自己去看一下源代码的实现。

综上可得std::decay其实就是利用模板特化机制来实现对类型进行筛选,将原始的、没有经过其它属性修饰的类型提取出来,以达到朽化类型的作用。

4、总结

本文先是介绍了C++11新增的std::is_samestd::decay这两个模板类的作用与使用方法,然后通过对源码进行分析,我们知道了这两个模板类的实现其实并不复杂,都是借助了模板特化机制来实现的,其实不止这两个,C++标准库的type_traits文件里面的内容基本都是使用类似的方法来实现的。

最后,如果大家觉得本文写得好的话麻烦点赞收藏关注一下谢谢,也可以关注该专栏,以后会有更多优质文章输出的。

C++11的std::is_same和std::decay使用与源码解析相关推荐

  1. C++的std::is_same与std::decay

    一.背景 有一个模板函数,函数在处理int型和double型时需要进行特殊的处理,那么怎么在编译期知道传入的参数的数据类型是int型还是double型呢? #include <iostream& ...

  2. The Wide and Deep Learning Model(译文+Tensorlfow源码解析) 原创 2017年11月03日 22:14:47 标签: 深度学习 / 谷歌 / tensorf

    The Wide and Deep Learning Model(译文+Tensorlfow源码解析) 原创 2017年11月03日 22:14:47 标签: 深度学习 / 谷歌 / tensorfl ...

  3. 面试官系统精讲Java源码及大厂真题 - 11 HashSet、TreeSet 源码解析

    11 HashSet.TreeSet 源码解析 更新时间:2019-09-16 19:37:35 成功的奥秘在于目标的坚定. --迪斯雷利 引导语 HashSet.TreeSet 两个类是在 Map ...

  4. [源码解析] 深度学习分布式训练框架 horovod (11) --- on spark --- GLOO 方案

    [源码解析] 深度学习分布式训练框架 horovod (11) - on spark - GLOO 方案 文章目录 [源码解析] 深度学习分布式训练框架 horovod (11) --- on spa ...

  5. 学生HTML个人网页作业作品 ~ 超级英雄11页面网页设计成品~ 学生网页设计作业源码

    学生HTML个人网页作业作品 ~ 超级英雄11页面网页设计成品~ 学生网页设计作业源码 临近期末, 你还在为HTML网页设计结课作业,老师的作业要求感到头大?HTML网页作业无从下手?网页要求的总数量 ...

  6. Apache IoTDB源码解析(0.11.2版本):Session的源码解析

    1. 声明 当前内容主要为解析Apache IoTDB 0.11.2版本的Session的源码解析 通过前面的Apache Thrift的Demo,可以发现iotdb中的server是使用了thrif ...

  7. C++演示std :: sort(),std :: reverse()的函数(附完整源码)

    @[TOC](C++演示std :: sort(),std :: reverse()的函数) C++演示std :: sort(),std :: reverse()的函数完整源码(定义,实现,main ...

  8. Linux0.11内核源码解析-setup.s

    学习资料: Linux内核完全注释 操作系统真像还原 极客时间-Linux内核源码趣读 Linux0.11内核源码 ->setup程序将system模块从0x10000~0x8ffff整块向下移 ...

  9. Linux0.11内核源码解析-bootsect.s

    学习资料: Linux内核完全注释 操作系统真像还原 极客时间-Linux内核源码趣读 Linux0.11内核源码 ->上电 ->80x86架构CPU会自动进入实模式 ->从地址0x ...

  10. 阿里 双11 同款,流量防卫兵 Sentinel go 源码解读

    作者 | 于雨  apache/dubbo-go 项目负责人 本文作者系 apache/dubbo-go 项目负责人,目前在 dubbogo 项目中已内置可用 sentinel-go,如果想单独使用可 ...

最新文章

  1. 2022-2028年中国塑料网格板行业市场行情动态及发展趋向分析报告
  2. 【linux】Valgrind工具集详解(九):Memcheck检查的内容和方法
  3. iOS中UISearchBar(搜索框)使用总结
  4. 去除菜单项的加速键--‘’符号
  5. JQuery-Table斑马线
  6. JQuery七个常犯的错误
  7. Java包装类型对象比较相等性注意事项
  8. 刷题记录 kuangbin带你飞专题五:并查集
  9. ppp协议 服务器,详解PPP及PPPoE协议
  10. 深度解析《软文广告经典案例300》
  11. 『IT视界』 [原创评论]揪出"程序员"身上的"六宗罪"
  12. MySQL数据库安全配置规范操作
  13. SpringCloud学习一
  14. HTML+CSS静态页面网页设计作业——我的家乡-四川成都(4页) HTML+CSS+JavaScript
  15. 工作篇 之 解决谷歌地图与 NestedScrollView 滑动冲突
  16. 虚拟机DEDECMS织梦建站
  17. 【MATLAB】理解采样频率和信号频率的关系
  18. 下载工具:aria2c
  19. 虚拟天文台主节点成功上云
  20. 帕斯卡分布/负二项分布

热门文章

  1. win10默认壁纸_Win10系统待机锁频壁纸怎么提取?
  2. Hou的图像显著性计算模型
  3. android 跳转公众号,app直接跳转公众号
  4. 湘潭大学 计算机学院程诗婕,2019 CCF CCSP分赛区竞赛决出金银铜奖
  5. CorelDRAW_X6使用汇总
  6. 学习笔记 - excel筛选分组
  7. [学习报告]《LeetCode零基础指南》(第五讲) 指针-gyro
  8. 终于!疫情之下,第一批企业没能熬住面临倒闭,员工被遣散,没能等来春暖花开!
  9. excel两列数据对比找不同_对比excel,轻松学习python数据分析
  10. WinPE (老毛桃最终修改版) V09.11 硬盘安装操作系统详细图解