C++11的std::is_same和std::decay使用与源码解析
Posted 彼 方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11的std::is_same和std::decay使用与源码解析相关的知识,希望对你有一定的参考价值。
C++11的std::is_same和std::decay源码解析
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_same
和std::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; // true
std::cout << std::is_same<double, double>::value << std::endl; // true
std::cout << std::is_same<int32_t, int32_t>::value << std::endl; // true
std::cout << std::is_same<int64_t, int64_t>::value << std::endl; // true
std::cout << std::endl << "第二组,类型相同,但是写法不同(typedef重命名了)" << std::endl;
std::cout << std::is_same<short, int16_t>::value << std::endl; // true
std::cout << std::is_same<int, int32_t>::value << std::endl; // true
std::cout << std::is_same<long, int64_t>::value << std::endl; // true
std::cout << std::is_same<unsigned int, uint32_t>::value << std::endl; // true
std::cout << std::endl << "第三组,类型不同" << std::endl;
std::cout << std::is_same<char, int>::value << std::endl; // false
std::cout << std::is_same<double, float>::value << std::endl; // false
std::cout << std::is_same<float, long>::value << std::endl; // false
std::cout << std::is_same<double, char>::value << std::endl; // false
std::cout << std::endl << "第四组,类型其实是一样的,只是省略写法而已" << std::endl;
std::cout << std::is_same<char, signed char>::value << std::endl; // false
std::cout << std::is_same<char, unsigned char>::value << std::endl; // false
std::cout << std::is_same<short, signed short>::value << std::endl; // true
std::cout << std::is_same<int, signed int>::value << std::endl; // true
std::cout << std::endl << "第五组,类型不同" << std::endl;
std::cout << std::is_same<char*, char[]>::value << std::endl; // false
std::cout << std::is_same<const char, char>::value << std::endl; // false
std::cout << std::is_same<const char&, const char>::value << std::endl; // false
std::cout << std::is_same<const int&, int>::value << std::endl; // false
}
上面的结果中,前三组应该是没啥歧义的,因为std::is_same
是可以识别出被typedef
、define
重命名的类型的原始类型的。第四组就有点意思了,除了前面两个以外都是true,说明std::is_same
是可以判断出signed
和signed+类型
是相同的。第五组的话也没什么好说的,类型确实不同。
这里解释一下,从上面的代码中看得出来,
char
既不是unsigned char
也不是signed char
,char
的表达数值范围可能等同于signed char
,也可能等同于unsigned char
,这取决于编译器,一般是等同于signed char
,但这仅仅是范围等同,就像32位机上int
和long
的数值范围是一样的,但并不是同一个类型。
2.2、std::decay使用方法
std::decay
人如其名,就是朽化的意思,主要是对一个类型进行朽化处理,说白一点就是将类型的一些属性比如const
、volatile
、&
(引用)等消除掉,需要注意指针是消不掉。首先通过一个例子看一下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 int
的const
属性就没了,这就是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; // true
std::cout << std::is_same<std::decay<const int>::type, std::decay<int>::type>::value << std::endl; // true
std::cout << std::is_same<std::decay<int&>::type, std::decay<int>::type>::value << std::endl; // true
std::cout << std::is_same<std::decay<const int>::type, std::decay<const volatile int>::type>::value << std::endl; // true
std::cout << std::is_same<std::decay<const volatile int&>::type, std::decay<int>::type>::value << std::endl; // true
std::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; };
可以看到共有三种偏特化形式:
- 第一种就是当
_Up
既不是数组形式也不是可调用实体形式时匹配,使用了std::remove_cv
去除了_Up
的const
和volatile
属性。关于std::remove_cv
可以看一下这篇文章《C++11的std::ref、std::cref源码解析》,里面有详细介绍 - 第二种就是当
_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; };
- 第三种就是当
_Up
是可调用实体时匹配,使用了std::add_pointer
去除了_Up
的引用属性,代码与前面的那些原理是一样的,这里就不细讲了,大家可以自己去看一下源代码的实现。
综上可得std::decay
其实就是利用模板特化机制来实现对类型进行筛选,将原始的、没有经过其它属性修饰的类型提取出来,以达到朽化类型的作用。
4、总结
本文先是介绍了C++11新增的std::is_same
和std::decay
这两个模板类的作用与使用方法,然后通过对源码进行分析,我们知道了这两个模板类的实现其实并不复杂,都是借助了模板特化机制来实现的,其实不止这两个,C++标准库的type_traits
文件里面的内容基本都是使用类似的方法来实现的。
最后,如果大家觉得本文写得好的话麻烦点赞收藏关注一下谢谢,也可以关注该专栏,以后会有更多优质文章输出的。
以上是关于C++11的std::is_same和std::decay使用与源码解析的主要内容,如果未能解决你的问题,请参考以下文章
使用std :: is_same和operator ||进行编译错误