开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
背景
定义在<type_traits>中,用于判断一个类型是否是void类型,是否是nullptr_t类型,属于基础的类型判断。
代码实现
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源码,这里仅用作相关原理分析。
实现分析
is_void
template<typename>
struct __is_void_helper
: public false_type { };
template<>
struct __is_void_helper<void>
: public true_type { };
/// is_void
template<typename _Tp>
struct is_void
: public __is_void_helper<typename remove_cv<_Tp>::type>::type
{ };
这里创建了一个__is_void_helper的辅助类,它的一般版本继承false_type(里面的value值为默认的false值),特化版本接受void参数,继承true_type(value值默认为true值),这就是模板的魅力,通过特化版本直接将void类型识别出来。最后在正式版本中,需要对输入的类型做remove_cv处理,去除掉const和volatile属性,然后再与void进行比较。
is_null_pointer
template<typename>
struct __is_null_pointer_helper
: public false_type { };
template<>
struct __is_null_pointer_helper<std::nullptr_t>
: public true_type { };
/// is_null_pointer (LWG 2247).
template<typename _Tp>
struct is_null_pointer
: public __is_null_pointer_helper<typename remove_cv<_Tp>::type>::type
{ };
这里的判断方式与is_void是类似的,也是使用了一个模板特化版本,如果类型为std::nullptr_t,则直接继承true_type。同样的也是要使用remove_cv去除const和volatile属性。
使用案例
#include <iostream>
#include <type_traits>
int main(){
std::cout << std::boolalpha;
std::cout << "int:\t" << std::is_void<int>::value << std::endl;
std::cout << "void:\t" << std::is_void<void>::value << std::endl;
std::cout << "nullptr is null_pointer:\t" << std::is_null_pointer<decltype(nullptr)>::value << std::endl;
std::cout << "int* is null_pointer:\t" << std::is_null_pointer<int*>::value << std::endl;
std::cout << "nullptr is pointer:\t" << std::is_pointer<decltype(nullptr)>::value << std::endl;
std::cout << "int* is pointer:\t" << std::is_pointer<int*>::value << std::endl;
return 0;
}
注意,上面的案例中,我们还检查了nullptr的类型std::nullptr_t是否是空指针,答案是true,但它并不是一个指针,因为在STL中nullptr_t实际上是一个类的定义,可以指向空指针,并不是一个指针类型,所以在判断它是否是指针时,会返回false。
总结
is_void和is_null_pointer分别用来判断一个类型是否是void或std::nullptr_t类型,均使用了模板特化的方法来实现,需要注意到std::nullptr_t是空指针类型,但却不是指针类型,因为它是STL的类实现。