C++ 中的 traits 是一种模板元编程技术,常用于提取或定义类型相关的元信息,如类型是否为指针、是否为整型、某个类的特征类型(例如值类型、迭代器类型)等。
Traits 的核心思想:
通过模板特化提取类型信息,使得类型推导、类型选择、编译期判断更加灵活。
一、Traits 的应用场景
-
类型判断:
- 判断是否为某种类型(如整型、指针类型)
-
类型选择:
- 通过条件选择不同类型(如
std::conditional
)
- 通过条件选择不同类型(如
-
函数重载选择(SFINAE):
- 根据类型不同选择不同实现
-
容器适配器:
- 提取容器的成员类型(如
value_type
、iterator
)
- 提取容器的成员类型(如
二、Traits 的基本结构
最简单的 Traits 模板结构如下:
template<typename T>
struct MyTraits {
static constexpr bool is_pointer = false;
};
template<typename T>
struct MyTraits<T*> {
static constexpr bool is_pointer = true;
};
用法:
MyTraits<int>::is_pointer // false
MyTraits<int*>::is_pointer // true
三、标准库中的类型 Traits
头文件 <type_traits>
提供了大量实用的类型 traits 工具。
常用类型 traits 示例:
trait | 说明 |
---|---|
std::is_integral<T> | 判断 T 是否为整型 |
std::is_floating_point<T> | 是否为浮点类型 |
std::is_pointer<T> | 是否为指针类型 |
std::remove_reference<T> | 去掉引用类型 |
std::remove_cv<T> | 去掉 const/volatile 修饰 |
std::conditional<C, T1, T2> | 若 C 为 true 选 T1,否则选 T2 |
std::enable_if<C, T> | 条件启用某个模板 |
std::is_same<T1, T2> | 判断两个类型是否相同 |
示例:使用 std::is_pointer
做分支
template<typename T>
void process(const T& value) {
if constexpr (std::is_pointer<T>::value) {
std::cout << "Pointer: " << *value << std::endl;
} else {
std::cout << "Value: " << value << std::endl;
}
}
C++17 中的 if constexpr
+ traits,可以在编译期消除无效分支。
四、自定义 Traits:提取嵌套类型
如想提取一个类的嵌套类型(如容器的 value_type
):
template<typename T>
struct ValueType {
using type = typename T::value_type;
};
使用:
ValueType<std::vector<int>>::type // int
结合 decltype
更直观:
template<typename T>
auto get_first(const T& container) -> typename T::value_type {
return *container.begin();
}
五、配合 std::enable_if
使用:SFINAE 风格
template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type
print_type(T val) {
std::cout << "Integral type\n";
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value>::type
print_type(T val) {
std::cout << "Floating point type\n";
}
这种做法允许根据类型属性选择不同函数定义(即 SFINAE:Substitution Failure Is Not An Error)。
六、Traits 的高级用法:类型分发
template<typename T>
struct AlgorithmSelector {
static void run(const T& t) {
std::cout << "General version\n";
}
};
template<typename T>
struct AlgorithmSelector<T*> {
static void run(const T* t) {
std::cout << "Pointer specialization\n";
}
};
template<typename T>
void process(const T& t) {
AlgorithmSelector<T>::run(t);
}
总结
特性 | 描述 |
---|---|
类型提取 | 获取类型的子类型,如 value_type , iterator |
类型判断 | 判断类型属性,如 is_pointer , is_integral |
编译期分支控制 | if constexpr , std::enable_if , std::conditional |
类型萃取 | 定义模板特化来提供编译期信息 |
SFINAE 与重载选择 | 类型 traits + enable_if 可精确控制函数模板匹配 |