开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
背景
定义在<type_traits>中,用于去除或者增加一个类型的const和volatile属性,属于比较基础的类型萃取技术。
代码实现
gcc官网:gcc.gnu.org/
gcc代码下载:mirrors.tuna.tsinghua.edu.cn/help/gcc.gi…
gcc版本代码:gcc-7.5.0(branch分支)
文件位置:gcc/libstdc++-v3/include/std/type_traits
注意:以下的代码实现省略了一些宏定义部分,实际的代码还是参考gcc源码,这里仅用作相关原理分析。
实现分析
std::add_const/std::remove_const
/// remove_const
template<typename _Tp>
struct remove_const
{ typedef _Tp type; };
template<typename _Tp>
struct remove_const<_Tp const>
{ typedef _Tp type; };
/// add_const
template<typename _Tp>
struct add_const
{ typedef _Tp const type; };
可以看到add_const是比较简单的,将输入类型加const修饰重定义为type即可;
remove_const需要多一个模板处理,如果是普通情况(没有const修饰),直接重定义输入类型即可,
多出来的模板是基础模板的一个特化版本,cover带有const属性的类型,去除const属性,重定义原类型为type即可。
注意,上面提到的模板特化将会在类型萃取中经常用到,用来覆盖某些特定类型的处理,这也是模板的一大优势。
std::add_volatile/std::remove_volatile
/// remove_volatile
template<typename _Tp>
struct remove_volatile
{ typedef _Tp type; };
template<typename _Tp>
struct remove_volatile<_Tp volatile>
{ typedef _Tp type; };
/// add_volatile
template<typename _Tp>
struct add_volatile
{ typedef _Tp volatile type; };
实现方式与const的操作基本一致,就不深入讲解了
std::remove_cv/std::add_cv
/// remove_cv
template<typename _Tp>
struct remove_cv
{
typedef typename
remove_const<typename remove_volatile<_Tp>::type>::type type;
};
/// add_cv
template<typename _Tp>
struct add_cv
{
typedef typename
add_const<typename add_volatile<_Tp>::type>::type type;
};
这里就是对上面的重复操作,需要注意的是,这里使用typename先获取remove_volatile之后的type类型,然后再调用remove_const,同样也是使用typename获取type类型,然后将其重定义为type类型;add_cv是相反的操作。
使用案例
#include <iostream>
#include <type_traits>
int main(){
typedef typename std::remove_cv<const int>::type type1;
typedef typename std::remove_cv<volatile int>::type type2;
typedef typename std::remove_cv<const volatile int>::type type3;
typedef typename std::remove_cv<const volatile int*>::type type4;
typedef typename std::remove_cv<int* const volatile>::type type5;
std::cout << std::boolalpha;
std::cout << "type1:const int\t\t\t" << std::is_same<type1,int>::value << "\t"
<< std::is_same<type1,const int>::value << std::endl;
std::cout << "type2:volatile int\t\t" << std::is_same<type2,int>::value << "\t"
<< std::is_same<type2,volatile int>::value << std::endl;
std::cout << "type3:const volatile int\t" << std::is_same<type3,int>::value << "\t"
<< std::is_same<type3,const volatile int>::value << std::endl;
std::cout << "type4:const volatile int*\t" << std::is_same<type4,int*>::value << "\t"
<< std::is_same<type4,const volatile int*>::value << std::endl;
std::cout << "type5:int* const volatile\t" << std::is_same<type5,int*>::value << "\t"
<< std::is_same<type5,int* const volatile>::value << std::endl;
return 0;
}
注意上面前三种类型进行比较时,结果都与我们预期的一样,在对const volatile int进行remove_cv操作时,我们要明白,前面的const volatile是针对指针指向的内容的修饰,而非对指针的修饰,所以remove_cv并不会去除const volatile,类型还是与const volatile int一样。
反过来将修饰符const volatile修饰指针,此时就能去除const volatile 变成int*指针。测试结果如下:
总结
std::remove_cv/std::remove_cv是类型萃取的基础部分,使用了模板特化的方式,可以将输入类型中的const volatile修饰去除或者增加,最后都以成员type的形式展现,在具体使用过程中可以方便地对输入类型进行增加修饰和去除修饰的操作。