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_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;         // 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是可以识别出被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;       // 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; };

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

  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文件里面的内容基本都是使用类似的方法来实现的。

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

  • 72
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 120
    评论
std::remove_cv和std::decay都是C++标准库中的模板类,用于处理类型的特性。 std::remove_cv用于移除类型中的const和volatile修饰符。在C++11中,我们需要使用typename std::remove_cv<T>::type的形式来获取移除修饰符后的类型。而在C++14及其后的标准中,我们可以使用std::remove_cv_t<T>的形式来简化代码。\[2\] std::decay用于对一个类型进行退化处理。它会移除类型中的引用修饰符,并将数组类型转换为指针类型。在C++11中,我们需要使用typename std::decay<T>::type的形式来获取退化后的类型。\[1\]在C++14及其后的标准中,我们可以使用std::decay_t<T>的形式来简化代码。\[2\] 总结来说,std::remove_cv用于移除类型中的const和volatile修饰符,而std::decay用于对类型进行退化处理,移除引用修饰符并将数组类型转换为指针类型。 #### 引用[.reference_title] - *1* [C++11std::is_same和std::decay使用源码解析](https://blog.csdn.net/weixin_43798887/article/details/118311126)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [【C++ 泛型编程 入门篇】C++模版中std::remove_reference_t和std::remove_cv_t的运用](https://blog.csdn.net/qq_21438461/article/details/131193312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++std::is_same与std::decay](https://blog.csdn.net/sinat_31608641/article/details/124598754)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 120
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彼 方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值