《C++ Primer Plus 6th.ed》读书笔记之四:简单的type_traits实现及其应用

关于

是C++自2011年标准后添加到STL中的一个头文件,正如其名,它提供了一系列模板类去确定类型的属性,例如:

// 检查传入类型参数是否为void
template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };

// 可以这样使用它
#include 
bool _v_flag = std::is_void<int>::value;  	// false
bool _i_flag = std::is_void<void>::value;	// true

更多具体示例见这里,本文以is_void<>为例,简单剖析一下对c++内建类型的实现方法
那么为什么不讲一下对自定义类型的实现呢?因为C++在编译时无法产生太多的元信息,因此无法进行模板替换与展开,这部分代码实现是直接写在编译器源码中的,而我又比较懒,不想去翻gcc的源码……

is_void<>模板展开

首先,is_void<>是一个模板类,只不过这个模板类是由struct定义的——除了成员访问权限默认为public,与class并无二致——它的源码在文章开头已经贴过了,这里再贴一遍:

template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };

可以看到,它以公开继承的方式继承了另外一个模板类__is_void_helper,看来这个类模板是我们下一步要找的目标,不过先看一下这个继承中的其他部分再去考虑这个基类的实现
其中remove_cv也是声明在该文件中一个类模板,但是在该文件中仅有声明而无实现,估计也是由编译器实现的吧,它的作用是抹去传入类型的const/volatile属性,例如传入类型参数为const void,那么其类型成员type将被指定为void,这样被继承的基类部分就变成了__is_void_helper::type
下面来看__is_void_helper<>的实现:

template<typename>
struct __is_void_helper : public false_type { };

template<>
struct __is_void_helper<void> : public true_type { }

这里可以看到,根据传入类型的不同,__is_void_helper<>具有两条不同的继承路线——传入void就继承true_type,否则继承false_type,那么下面继续看这两个不同基类的实现:

/// The type used as a compile-time boolean with true value.
typedef integral_constant<bool, true>     true_type;

/// The type used as a compile-time boolean with false value.
typedef integral_constant<bool, false>    false_type;

显然这两个基类是对同一个类型不同参数的类型重定义,那么找到这个intergral_constant至关重要:

template<typename _Tp, _Tp __v>
struct integral_constant
{
	static constexpr _Tp                  value = __v;
	typedef _Tp                           value_type;
	typedef integral_constant<_Tp, __v>   type;
	constexpr operator value_type() const noexcept { return value; }
}

这个时候就一目了然了,根据is_void<>传入的类型参数不同,最后继承的integral_constant也不同,整个模板的展开过程大致如下图所示:

void
non-void
is_void<>
__is_void_helper< void >
__is_void_helper< typename T >
integral_constant< bool, true >
is_void< void >::value = true
integral_constant< bool, false >
is_void< void >::value = false

新标准中的

在C++14/17中,对该头文件进行了多处修改,其中比较重要的有两处:

  1. C++14中,对integral_constant模板添加了operator()的重载:

    constexpr value_type operator() const noexcept { return value; }
    

    这意味着可以将该模板作为函数对象(functional object)传递,也可以用这样的方式获取类型判断的结果:

    bool _v_flag = std::is_void<void>(); // true
    
  2. C++17中,添加了一种直接获取integral_constant::value的模板变量,它具有这样的通用命名方式is_type_v<>
    针对上例,可以这样获取类型判断的结果:

    bool _v_flag = std::is_void_v<void>; // true
    

    但是要注意,在目前主流编译器(GCC/MSVC)中默认使用的C++标准似乎是C++14从而导致编译失败,针对GCC可以在编译命令中添加--std=c++17或者--std=c++2a解决这个问题

你可能感兴趣的:(C/C++)