C++ <type_traits>
应用详解
<type_traits>
是 C++ 标准库中的一个头文件,提供了编译时类型检查、类型转换和类型特性查询的工具。它广泛应用于模板元编程(Template Metaprogramming)、SFINAE(Substitution Failure Is Not An Error)、类型推导优化等场景。
1. <type_traits>
的核心作用
<type_traits>
主要提供以下功能:
- 类型检查(Type Traits):判断类型是否满足某些条件(如
is_integral
、is_pointer
)。 - 类型转换(Type Transformations):修改类型(如
remove_pointer
、add_const
)。 - SFINAE 辅助:用于模板特化或重载决议。
- 编译时逻辑控制:结合
if constexpr
或 static_assert
进行条件编译。
2. 常用类型检查(Type Traits)
2.1 基本类型检查
特性 | 作用 | 示例 |
---|
std::is_void<T> | 检查 T 是否是 void | is_void<void>::value → true |
std::is_integral<T> | 检查 T 是否是整数类型 | is_integral<int>::value → true |
std::is_floating_point<T> | 检查 T 是否是浮点类型 | is_floating_point<float>::value → true |
std::is_array<T> | 检查 T 是否是数组 | is_array<int[3]>::value → true |
std::is_pointer<T> | 检查 T 是否是指针 | is_pointer<int*>::value → true |
std::is_reference<T> | 检查 T 是否是引用 | is_reference<int&>::value → true |
std::is_const<T> | 检查 T 是否是 const 修饰 | is_const<const int>::value → true |
std::is_volatile<T> | 检查 T 是否是 volatile 修饰 | is_volatile<volatile int>::value → true |
std::is_same<T, U> | 检查 T 和 U 是否相同 | is_same<int, int32_t>::value → true (依赖平台) |
示例:检查类型是否为整数
#include <iostream> |
#include <type_traits> |
|
template<typename T> |
void check_integral() { |
if constexpr (std::is_integral_v<T>) { // C++17 起支持 _v 后缀 |
std::cout << "T is integral type." << std::endl; |
} else { |
std::cout << "T is NOT integral type." << std::endl; |
} |
} |
|
int main() { |
check_integral<int>(); // 输出: T is integral type. |
check_integral<float>(); // 输出: T is NOT integral type. |
return 0; |
} |
2.2 复合类型检查
特性 | 作用 | 示例 |
---|
std::is_class<T> | 检查 T 是否是类类型 | is_class<std::string>::value → true |
std::is_union<T> | 检查 T 是否是联合体 | is_union<union{}>::value → true |
std::is_enum<T> | 检查 T 是否是枚举 | enum E { A }; is_enum<E>::value → true |
std::is_function<T> | 检查 T 是否是函数 | is_function<void()>::value → true |
std::is_member_pointer<T> | 检查 T 是否是成员指针 | is_member_pointer<int MyClass::*>::value → true |
示例:检查类型是否为类
#include <iostream> |
#include <type_traits> |
|
struct MyClass {}; |
|
template<typename T> |
void check_class() { |
if constexpr (std::is_class_v<T>) { |
std::cout << "T is a class." << std::endl; |
} else { |
std::cout << "T is NOT a class." << std::endl; |
} |
} |
|
int main() { |
check_class<MyClass>(); // 输出: T is a class. |
check_class<int>(); // 输出: T is NOT a class. |
return 0; |
} |
3. 类型转换(Type Transformations)
<type_traits>
提供了一些编译时类型修改的工具:
特性 | 作用 | 示例 |
---|
std::remove_const<T> | 移除 const 修饰 | remove_const<const int>::type → int |
std::remove_volatile<T> | 移除 volatile 修饰 | remove_volatile<volatile int>::type → int |
std::remove_cv<T> | 移除 const 和 volatile | remove_cv<const volatile int>::type → int |
std::remove_pointer<T> | 移除指针 | remove_pointer<int*>::type → int |
std::remove_reference<T> | 移除引用 | remove_reference<int&>::type → int |
std::add_const<T> | 添加 const 修饰 | add_const<int>::type → const int |
std::add_volatile<T> | 添加 volatile 修饰 | add_volatile<int>::type → volatile int |
std::add_pointer<T> | 添加指针 | add_pointer<int>::type → int* |
std::add_lvalue_reference<T> | 添加左值引用 | add_lvalue_reference<int>::type → int& |
std::add_rvalue_reference<T> | 添加右值引用 | add_rvalue_reference<int>::type → int&& |
std::decay<T> | 模拟值传递(移除引用、const 、数组/函数转指针) | decay<int&>::type → int |
示例:移除 const
和引用
#include <iostream> |
#include <type_traits> |
|
int main() { |
using T1 = const int&; |
using T2 = std::remove_const_t<std::remove_reference_t<T1>>; // C++14 起支持 _t 后缀 |
std::cout << std::is_same_v<T2, int> << std::endl; // 输出: 1 (true) |
return 0; |
} |
4. SFINAE 应用
SFINAE(Substitution Failure Is Not An Error)是一种模板特化技巧,结合 <type_traits>
可以实现编译时分支选择。
4.1 基本 SFINAE 示例
#include <iostream> |
#include <type_traits> |
|
// 仅当 T 是整数类型时启用 |
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>> |
void process_integral(T value) { |
std::cout << "Processing integral: " << value << std::endl; |
} |
|
// 仅当 T 是浮点类型时启用 |
template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>> |
void process_floating(T value) { |
std::cout << "Processing floating: " << value << std::endl; |
} |
|
int main() { |
process_integral(42); // 输出: Processing integral: 42 |
process_floating(3.14); // 输出: Processing floating: 3.14 |
// process_integral(3.14); // 编译错误: no matching function |
return 0; |
} |
4.2 更复杂的 SFINAE
#include <iostream> |
#include <type_traits> |
|
// 如果 T 是指针,返回 true |
template<typename T> |
auto is_pointer_v = std::is_pointer_v<T>; |
|
// SFINAE 示例:仅当 T 不是指针时启用 |
template<typename T, typename = std::enable_if_t<!is_pointer_v<T>>> |
void foo(T value) { |
std::cout << "Non-pointer: " << value << std::endl; |
} |
|
int main() { |
foo(42); // 输出: Non-pointer: 42 |
// foo(nullptr); // 编译错误: no matching function |
return 0; |
} |
5. C++17 改进:if constexpr
C++17 引入了 if constexpr
,可以替代部分 SFINAE 用法,使代码更简洁:
#include <iostream> |
#include <type_traits> |
|
template<typename T> |
void check_type(T value) { |
if constexpr (std::is_integral_v<T>) { |
std::cout << "Integral: " << value << std::endl; |
} else if constexpr (std::is_floating_point_v<T>) { |
std::cout << "Floating: " << value << std::endl; |
} else { |
std::cout << "Unknown type" << std::endl; |
} |
} |
|
int main() { |
check_type(42); // 输出: Integral: 42 |
check_type(3.14); // 输出: Floating: 3.14 |
check_type("hello"); // 输出: Unknown type |
return 0; |
} |
6. 总结
功能 | 示例 |
---|
类型检查 | is_integral<T> , is_pointer<T> |
类型转换 | remove_const<T> , add_pointer<T> |
SFINAE | enable_if_t<condition> |
C++17 简化 | if constexpr |
<type_traits>
是 C++ 模板元编程的核心工具,广泛应用于:
- 编译时类型检查(如
static_assert
)。 - 模板特化(SFINAE)。
- 优化类型推导(如
std::decay
)。 - C++17 后结合
if constexpr
简化代码。
掌握 <type_traits>
可以写出更高效、更灵活的模板代码!