Featured image of post 类型萃取

类型萃取

类型萃取技术

引言

在C++中,类型萃取(Type Traits)是一种在编译时获取和操作类型信息的机制。它通过模板元编程技术实现,允许开发者根据类型的特性进行条件编译或执行不同的代码路径。类型萃取类通常定义在<type_traits>头文件中。

常见类型萃取类

std::is_* 系列

这些类型萃取类用于检查类型是否符合某种条件。

  • std::is_integral<T>:检查类型 T 是否为整数类型。
  • std::is_floating_point<T>:检查类型 T 是否为浮点类型。
  • std::is_pointer<T>:检查类型 T 是否为指针类型。
  • std::is_reference<T>:检查类型 T 是否为引用类型。
  • std::is_array<T>:检查类型 T 是否为数组类型。
  • std::is_function<T>:检查类型 T 是否为函数类型。
  • std::is_const<T>:检查类型 T 是否为常量类型。
  • std::is_volatile<T>:检查类型 T 是否为易失类型。
  • std::is_class<T>:检查类型 T 是否为类类型。
  • std::is_union<T>:检查类型 T 是否为联合体类型。

std::is_*_v 系列(C++17引入)

这些是 std::is_* 系列的变量模板版本,简化了使用方式。

  • std::is_integral_v<T>:如果 T 是整数类型,返回 true,否则返回 false
  • std::is_floating_point_v<T>:如果 T 是浮点类型,返回 true,否则返回 false

std::is_same<T, U>

  • std::is_same<T, U>:检查类型 TU 是否相同。
  • std::is_same_v<T, U>:这是 std::is_same<T, U> 的变量模板版本。

std::remove_* 系列

这些类型萃取类用于修改类型(如去除常量、指针等)。

  • std::remove_const<T>:去除类型 T 的常量修饰符。
  • std::remove_volatile<T>:去除类型 T 的易失修饰符。
  • std::remove_cv<T>:去除类型 T 的常量和易失修饰符。
  • std::remove_reference<T>:去除类型 T 的引用。
  • std::remove_pointer<T>:去除类型 T 的指针。
  • std::remove_extent<T>:去除类型 T 的数组维度。

std::is_base_of<Base, Derived>std::is_convertible<From, To>

  • std::is_base_of<Base, Derived>:检查 Derived 是否是 Base 的派生类。
  • std::is_convertible<From, To>:检查类型 From 是否能转换为类型 To

std::enable_if<T, U>std::disable_if<T, U>

  • std::enable_if<T, U>:当 T 为真时,启用类型 U
  • std::disable_if<T, U>:当 T 为真时,禁用类型 U

std::is_trivially_* 系列(C++11引入)

这些类型萃取类用于检查类型是否具有某些简单的特性,如无构造函数、无拷贝构造函数等。

  • std::is_trivially_copyable<T>:检查类型 T 是否是一个 trivially copyable 类型(可以直接内存拷贝的类型)。
  • std::is_trivially_constructible<T>:检查类型 T 是否可以通过简单的构造函数构造。
  • std::is_trivially_destructible<T>:检查类型 T 是否有简单的析构函数。

std::conditional<T, U, V>(C++11引入)

这个类型萃取类根据条件 T 选择类型 UV

  • std::conditional<T, U, V>:如果 T 为真,则类型为 U,否则为 V

is_integral<T>的实现

使用模板特化实现简单的类型萃取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template<typename T>
class my_is_integral {
public:
    static constexpr bool value = false;
};

//特化版本
template<> class my_is_integral<int> : public std::true_type {};

// 下面这些类型也是integral类型,后面的讨论不再全部写出来
template<> class my_is_integral<bool> : public std::true_type {};
template<> class my_is_integral<char> : public std::true_type {};
template<> class my_is_integral<signed char> : public std::true_type {};
template<> class my_is_integral<unsigned char> : public std::true_type {};
template<> class my_is_integral<short> : public std::true_type {};
template<> class my_is_integral<unsigned short> : public std::true_type {};
template<> class my_is_integral<unsigned int> : public std::true_type {};
template<> class my_is_integral<long> : public std::true_type {};
template<> class my_is_integral<unsigned long> : public std::true_type {};
template<> class my_is_integral<long long> : public std::true_type {};
template<> class my_is_integral<unsigned long long> : public std::true_type {};
template<> class my_is_integral<wchar_t> : public std::true_type {};
template<> class my_is_integral<char16_t> : public std::true_type {};
template<> class my_is_integral<char32_t> : public std::true_type {};

基于c++14的变量的模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
template<typename T>
class my_is_integral {
public:
    static constexpr bool value = false;
};

//特化版本
template<> class my_is_integral<int> : public std::true_type {};

//变量的模板,可以之间使用my_is_intergral_value<int>作为true or false
template<typename T>
constexpr bool my_is_integral_value = my_is_integral<T>::value;

解决修饰符问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
template<typename T>
class my_is_integral_helper {
public:
    static constexpr bool value = false;
};

//特化版本
template<> class my_is_integral_helper<int> : public std::true_type {};


//使用helper类
//my_is_integral继承了helper类并且使用remove_cv_t消除了cv限定符
template<typename T>
class my_is_integral : public my_is_integral_helper<std::remove_cv_t<T>> {};

template<typename T>
constexpr bool my_is_integral_value = my_is_integral<T>::value;

这样,就基本实现了自己的is_integral类了