c++11—type_traits
类型萃取即对类型进行操作,例如获取类型的名称、去除类型的修饰符、增加“类型”的修饰符。c++11的头文件#include <type_traits>中提供了很多的类模板帮助我们对类型进行萃取。下面对一些常见的类型萃取进行说明。
常量的萃取
integral_constant
用于获取某个类型静态常量,声明如下:
template<class T, T v> |
这里额外提供了两个bool的常量值std::true_type和std::false_type,标准库中的声明如下,这两个常量对于其他萃取器的实现有非常大作用:
typedef integral_constant<bool, true> true_type; |
类型种类的萃取
这种萃取能帮助我们判断一个类型是否是整形还是浮点型等。
is_integral
判断一个类型是否是整形,声明如下:
template<class T> |
简单的使用:
// std::is_integral<T>::value |
可以利用模板的偏特化实现一个简单版本:
|
为了方便使用,c++17新增了对应的变量模板,拥有成员变量value的萃取类一般都提供了变量模板:
template<class T> |
…
下面是一些主要的类型种类萃取。
| 类模板 | 用途 |
|---|---|
is_void |
检查类型是否是void |
is_array |
检查类型是否是array |
is_enum |
检查类型是否是enum |
is_union |
检查类型是否是union |
is_class |
检查类型是否是class |
is_pointer |
检查类型是否是指针类型 |
is_function |
检查类型是否是函数类型 |
is_lvalue_reference |
检查类型是否是左值引用 |
is_rvalue_reference |
检查类型是否是右值引用 |
is_member_object_pointer |
检查类型是否是指向非静态成员对象的指针 |
is_member_function_pointer |
检查类型是否是指向非静态成员函数的指针 |
类型属性的萃取
这种萃取能帮助我们判断一个类型是否拥有某些属性。
is_const
判断一个类型是否是const限定的,声明如下:
template<class T> |
可以利用偏特化实现,标准库中的实现:
template<typename> |
…
| 类模板 | 用途 |
|---|---|
is_volatile |
检查类型是否是volatile限定的 |
is_abstract |
检查是否是抽象类类型 |
| … | … |
某类属性增删的萃取
remove_const
去除类型的const属性,声明如下:
template< class T > |
标准库中的实现:
template<typename _Tp> |
在c++11中的使用:
std::remove_const<T>::type; |
为了简化使用,在c++14中提供了对应的别名模板,拥有type类型的萃取类一般都提供别名模板:
template< class T > |
相应的remove_volatile和remove_cv与之类似。
add_volatile
给类型增加volatile属性,声明如下:
template< class T > |
标准库中的实现:
template<typename _Tp> |
相应的add_const和add_cv与之类似。
…
| 类模板 | 用途 |
|---|---|
remove_const |
去除类型的const属性 |
remove_volatile |
去除类型的volatile属性 |
remove_cv |
去除类型的const和volatile属性 |
remove_reference |
去除给定类型的引用,包括左值引用和右值引用 |
add_const |
给类型增加const属性 |
add_volatile |
给类型增加volatile属性 |
add_cv |
给类型增加const和volatile属性 |
remove_pointer |
去除类型的指针属性 |
add_pointer |
给一个类型增加指针的属性 |
| … | … |
类型间关系的萃取
is_same
判断两个类型是否相同,声明如下:
template<class T, class U> |
标准库中的实现:
template<typename, typename> |
简单的使用:
// c++11 |
is_base_of
检查一个类型是否派生于其他类型,声明如下:
template<class Base, class Derived> |
is_convertible
检查一个类型是否能转换成另一个类型,声明如下:
template<class From, class To> |
简单的使用:
// c++14 |
is_invocable(c++17)
检查给定的函数、函数对象、函数指针或成员函数指针是否可以用给定的参数类型进行调用,声明如下:
template<class Fn, class... ArgTypes> |
…
| 类模板 | 用途 |
|---|---|
is_same |
检查两个类型是否相同 |
is_base_of |
检查一个类型是否派生于其他类型 |
is_convertible |
检查一个类型是否能转换成其他类型 |
is_invocable |
检查给定的函数、函数对象、函数指针或成员函数指针是否可以用给定的参数类型进行调用 |
| … | … |
支持某类操作的萃取
is_default_constructible
检查类型是否拥有默认构造函数,声明如下:
template< class T > |
简单的使用:
// c++11 |
可以利用SFINAE特性排除偏特化的方式来实现,可能的实现方式:
|
…
| 类模板 | 用途 |
|---|---|
is_default_constructible |
检查类型是否拥有默认构造函数 |
is_constructible |
检查类型是否拥有构造函数 |
is_copy_constructible |
检查类型是否拥有拷贝构造函数 |
has_virtual_destructor |
检查类型是否拥有虚析构函数 |
| … | … |
各种变化的萃取
decay
能去除const、volatile的修饰,去除引用,将数组类型转换成指针,将函数类型转换成函数指针类型。声明如下:
template<class T> |
简单的使用:
// c++11 |
decay可能的简单实现如下:
|
void_t
能够检测出应用SFINAE特性时出现的非法类型。传入到std::void_t中的类型必须是一个有效的类型。定义如下:
template< class... > |
用来探测类变量的实例:
|
enable_if
有条件的从重载解析中删除函数重载和模板特化,声明如下:
template<bool B, class T = void> |
只有当判断条件为true时,enable_if<...>::type才会存在,type类型和T保持一致,默认是void。
简单的使用:
|
conditional
条件选择萃取类型,声明如下:
template<bool B, class T, class F> |
如果B为true,则conditional<...>::type的类型是T,否则就是F。
简单的使用:
|
invoke_result
获取可调用对象输入一组参数后返回结果的类型,声明如下:
template<class F, class... ArgTypes> |
有一个类模板result_of也是差不多的效果,不过在c++17就不推荐使用了。在c++20的时候又增加了一个函数模板invoke对类模板invoke_result进行简单的封装,声明如下:
template<class F, class... Args> |
参考
- https://en.cppreference.com/w/cpp/header/type_traits
- 《c++ template 第二版》
