C++学习---类型萃取---混合类型判断

144 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情

背景

定义在<type_traits>中,用于判断一个类型是否是如下的混合类型:

  • is_reference:是否是引用类型
  • is_arithmetic:是否是算术类型
  • is_fundamental:是否是基础类型
  • is_object:是否是对象
  • is_member_pointer:是否是成员指针
  • is_scalar:是否是数据类型,可进行计算
  • is_compound:是否是复合类型

代码实现

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_reference

判断_Tp是否是左值引用或右值引用,借助__or_得到最终的结果。

  /// is_reference
  template<typename _Tp>
    struct is_reference
    : public __or_<is_lvalue_reference<_Tp>,
                   is_rvalue_reference<_Tp>>::type
    { };

is_arithmetic

判断_Tp是否是int类型或者浮点类型。

  /// is_arithmetic
  template<typename _Tp>
    struct is_arithmetic
    : public __or_<is_integral<_Tp>, is_floating_point<_Tp>>::type
    { };

is_fundamental

判断基础类型:算术类型,void类型,null_pointer类型。

  /// is_fundamental
  template<typename _Tp>
    struct is_fundamental
    : public __or_<is_arithmetic<_Tp>, is_void<_Tp>,
           is_null_pointer<_Tp>>::type
    { };

is_object

类型_Tp不是函数、引用、void之一,被认为是对象类型。

  /// is_object
  template<typename _Tp>
    struct is_object
    : public __not_<__or_<is_function<_Tp>, is_reference<_Tp>,
                          is_void<_Tp>>>::type
    { };

is_member_pointer

成员指针主要是通过对指针_Tp _Cp::*的识别,默认继承false_type,注意在最开始的位置我们需要调用remove_cv去除const和volatile属性。

  template<typename _Tp>
    struct __is_member_pointer_helper
    : public false_type { };

  template<typename _Tp, typename _Cp>
    struct __is_member_pointer_helper<_Tp _Cp::*>
    : public true_type { };

  /// is_member_pointer
  template<typename _Tp>
    struct is_member_pointer
    : public __is_member_pointer_helper<typename remove_cv<_Tp>::type>::type
    { };

is_scalar

数据类型包括算术类型,枚举类型,以及所有的指针类型(普通指针,成员指针,空指针)。

  /// is_scalar
  template<typename _Tp>
    struct is_scalar
    : public __or_<is_arithmetic<_Tp>, is_enum<_Tp>, is_pointer<_Tp>,
                   is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type
    { };

is_compound

复合类型:不是基础类型的都是复合类型

 /// is_compound
  template<typename _Tp>
    struct is_compound
    : public integral_constant<bool, !is_fundamental<_Tp>::value> { };

使用案例

#include <iostream>
#include <type_traits>

class A{};
enum E{e};

int main(){
#define LINE(x) std::cout << #x " ?: " << x << "\n"
    std::cout << std::boolalpha;
    std::cout << "------is_reference------\n";
    LINE(std::is_reference<int&>::value);
    LINE(std::is_reference<int&&>::value);
    LINE(std::is_reference<int*&>::value);
    LINE(std::is_reference<int*&&>::value);
    std::cout << "------is_arithmetic------\n";
    LINE(std::is_arithmetic<int>::value);
    LINE(std::is_arithmetic<bool>::value);
    LINE(std::is_arithmetic<char>::value);
    LINE(std::is_arithmetic<char*>::value);
    LINE(std::is_arithmetic<char&>::value);
    std::cout << "------is_fundamental------\n";
    LINE(std::is_fundamental<int>::value);
    LINE(std::is_fundamental<float>::value);
    LINE(std::is_fundamental<int*>::value);
    LINE(std::is_fundamental<float&>::value);
    std::cout << "------is_object------\n";
    LINE(std::is_object<int>::value);
    LINE(std::is_object<float>::value);
    LINE(std::is_object<A>::value);
    LINE(std::is_object<int*>::value);
    LINE(std::is_object<float&>::value);
    std::cout << "------is_member_pointer------\n";
    LINE(std::is_member_pointer<int(A::*)>::value);
    LINE(std::is_member_pointer<int*>::value);
    std::cout << "------is_scalar------\n";
    LINE(std::is_scalar<int>::value);
    LINE(std::is_scalar<decltype(E::e)>::value);
    LINE(std::is_scalar<int*>::value);
    LINE(std::is_scalar<int(A::*)>::value);
    std::cout << "------is_compound------\n";
    LINE(std::is_compound<int>::value);
    LINE(std::is_compound<A>::value);
    LINE(std::is_compound<E>::value);
    return 0;
}

基本上就是对前面类型的总结和组合,测试结果如下:

总结

  • is_reference:是否是引用类型
  • is_arithmetic:是否是算术类型
  • is_fundamental:是否是基础类型
  • is_object:是否是对象
  • is_member_pointer:是否是成员指针
  • is_scalar:是否是数据类型,可进行计算
  • is_compound:是否是复合类型