【C++11学习笔记】类型判断的type_traits学习

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

【C++11学习笔记】类型判断的type_traits学习
⼀、简单的type_traits
我理解的type_traits是利⽤C++模板特性和static、enum特性定义编译器常量,例如
1// TEMPLATE CLASS integral_constant
2 template<class _Ty,
3 _Ty _Val>
4struct integral_constant
5 { // convenient template for integral constant types
6static constexpr _Ty value = _Val;
7
8 typedef _Ty value_type;
9 typedef integral_constant<_Ty, _Val> type;
10
11 constexpr operator value_type() const _NOEXCEPT
12 { // return stored value 重载了强制转换(例如(bool)integral_constant<bool,true> 将会返回value值true)
13return (value);
14 }
15
16 constexpr value_type operator()() const _NOEXCEPT
17 { // return stored value 重载了()(例如, integral_constant<bool, true)() 将会返回value值 true)
18return (value);
19 }
20 };
这⾥利⽤的是static常量为编译器常量的特点,定义了value。

使⽤⽅法:从std::integral_constant派⽣,⽆需⾃⼰定义static const常量或enum类型,
std有两个定义好的std::integral_constant实例,分别定义了编译期的true和false类型,⽤途很⼴:
1 typedef integral_constant<bool, true> true_type;
2 typedef integral_constant<bool, false> false_type;
⼆、常见类型判断type_traits源码学习
1.is_void
声明:
template<class T>
struct is_void;
作⽤:
T是否为void类型
源码:
1 template<class T, class U>
2struct is_same : std::false_type
3 {};
4
5 template<class T>
6struct is_same : std::true_type
7 {};
8
9 template<class T>
10struct is_void : std::is_same<void, typename std::remove_cv<T>::type>
11 {};
说明:⾸先利⽤模板的匹配实现⽤以判断两种类型是否⼀致的is_name,再将T去除c(const)、v(volatile)限定符后与void类型判断是否⼀致。

下⾯有些简单的代码就不解释
了。

2.is_floating_point
声明
1 template< class T >
2struct is_floating_point;
作⽤
T是否为浮点类型
源码
1 template< class T >
2struct is_floating_point : std::integral_constant<bool,std::is_same<float, typename std::remove_cv<T>::type>::value || std::is_same<double, typename std::remove_cv<T>::type>::value || std::is_same<long double, typename std::remove_cv< 3 {};
3.is_array
声明
1 template<class T>
2struct is_array;
作⽤
T是否为数组类型
源码
1 template<class T>
2struct is_array : std::false_type {};
3
4 template<class T>
5struct is_array<T[]> : std::true_type {};
6
7 template<class T, std::size_t N>
8struct is_array<T[N]> : std::true_type {};
4.is_pointer
声明
1 template< class T >
2struct is_pointer;
作⽤
T是否为指针类型(包括函数指针,但不包括成员(函数)指针)
源码
1 template< class T > struct is_pointer_helper : std::false_type {};
2 template< class T > struct is_pointer_helper<T*> : std::true_type {};
3 template< class T > struct is_pointer : is_pointer_helper<typename std::remove_cv<T>::type> {};
5.is_member_pointer
声明
1 template< class T >
2struct is_member_pointer
作⽤
T是否为成员函数指针、指向成员变量指针类型
源码
1 template< class T >
2struct is_member_pointer_helper : std::false_type {};
3
4 template< class T, class U >
5struct is_member_pointer_helper<T U::*> : std::true_type {};
6
7 template< class T >
8struct is_member_pointer : is_member_pointer_helper<typename std::remove_cv<T>::type>
9 {};
为什么is_member_pointer_helper< T U::*>这个就是成员函数指针、指向成员变量指针类型呢?
这个参数T U::*怎么理解,其实就理解成T *——T类型指针,但是是类U中的,即类U的成员函数指针或成员变量指针,看下⾯的测试代码:
1 #include <iostream>
2 #include <type_traits>
3
4int main() {
5class cls {};
6 std::cout << (std::is_member_pointer<int(cls::*)>::value
7 ? "T is member pointer"
8 : "T is not a member pointer") << '\n';
9 std::cout << (std::is_member_pointer<int cls::*>::value
10 ? "T is member pointer"
11 : "T is not a member pointer") << '\n';
12 }
输出是
T is member pointer
T is member pointer
注意,并不是判断类T中是否真的有返回值为int的函数,或者是否有int型变量,⽽是只是判断T这个写法是否是成员函数指针、指向成员变量指针类型。

6.is_class
声明:
1 template <class T>
2struct is_class;
作⽤
T是否为类类型,且不是union类型
源码
1namespace detail {
2 template <class T> char test(int T::*);
3struct two { char c[2]; };
4 template <class T> two test(...);
5 }
6
7 template <class T>
8struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1 && !std::is_union<T>::value>
9 {};
解释⼀下,定义了两个模板函数,⼀个形参是int T::*(指向int型类成员变量的指针),返回值是char(⼤⼩是1);另⼀个形参是所有类型,返回值是struct two(⼤⼩是2)。

is_class继承了std::integral_constant< T, T v >(内部定义了⼀个static const T类型变量value,取值为v),value的类型为bool,当detail::test(0)的⼤⼩为1时(只要T是class类型,就符合第⼀个模板函数test,则其返回值⼤⼩就为1,否则返回值⼤⼩为2),并且不为union类型时(加上这个是因为,union类型类似struct类型,也⽀持T::*),则为class(或struct)类型。

7.is_base_of
声明
1 template <typename Base, typename Derived>
2class is_base_of;
作⽤
Base是否是Derived的基类
源码
1 template <typename Base, typename Derived,
2bool = (is_class<Base>::value && is_class<Derived>::value)>
3class is_base_of
4 {
5 template <typename T>
6static char helper(Derived, T);
7static int helper(Base, int);
8struct Conv
9 {
10operator Derived();
11operator Base() const;
12 };
13public:
14static const bool value = sizeof(helper(Conv(), 0)) == 1;
15 };
16
17
18 template <typename Base, typename Derived>
19class is_base_of<Base, Derived, false>
20 {
21public:
22static const bool value = is_same<Base, Derived>::value;
23 };
24
25
26class B
27 {
28 };
29
30class D : public B
31 {
32 };
33
34int main()
35 {
36 cout << boolalpha << is_base_of<B, D>::value << endl;
37 }
代码中最“厉害”的地⽅就是对helper函数的匹配了。

1. 如果Base不是Derived的基类,那么Conv()做隐式转换时,两个候选类型Base和Derived都是平等的,两个helper函数都可以匹配,但在这⾥按照规则,会去优先匹配⾮模
板的函数。

于是得到了我们想要的结果。

2. 如果Base是Derived的基类,这种情况⽐较复杂。

这种情况下,除⾮Conv对象是⼀个const的,否则它的隐式转换是只会去调⽤operator ()Derived的,因为operator ()Base const后⾯所带的const。

于是这样的情况下,Conv()总是隐式转换成⼀个Derived对象(当然,上⾯的只是学习代码,如果真正要实⽤的话,还要做很多⼯作,⽐如说在这⾥就要⾸先确保Derived类型本⾝不是const的),这时候对于两个helper的第⼀个参数,⼀个是精确匹配,⼀个是要转换为基类,⼀开始我异想天开地以为这种情况下就会去先匹配第⼀个了,因为这也是所需要的正确结果,结果⾃然是没有错,不过我的想法却是太天真了,因为我完全抹杀了第⼆个参数的贡献,倘若没有它,那第⼀个helper函数都不会被具现化,更别说让它去被匹配了。

相关文档
最新文档