所谓Type trait提供一种用来处理type属性的办法。它是一个模板,可在编译器根据一或多个模板实参产出一个type或value
示例如下:
针对整数类型的弹性重载
假设有一个函数foo(),对于整数类型和浮点数类型的实参,它该有不同的实现。通常的做法是将它重载,使它拥有针对整数类型和针对浮点数类型两个版本:
void foo(short);
void foo(int);
void foo(float);
void foo(double);
void foo(long double);
...
这样的重复工作不仅令人厌烦,还带来一个问题:只要面对新类型或用户自定义的类型,它就束手无策了
有了type trait
,你可以这样写:
template<typename T>
void foo_impl(T val, true_type);
template<typename T>
void foo_impl(T val, false_type);
template<typename T>
void foo(T val)
{
foo_impl(val, std::is_integral<T>());
}
处理共通类型
不同类型的两个值的总和或最小值就该使用所谓的共通类型。否则,如果我想实现一个函数,判断不同类型的两值中的最小值,其返回类型该是什么呢?
template<typename T1, typename T2>
???min(const T1 & x, const T2 & x);
如果使用type trait,可以像这样解决问题:
template<typename T1, typename T2>
typename std::common_type<T1,T2>::type min(const T1 & x, const T2 & y);
如果两个实参是int 或都是long,或一个是int一个是long,会产出int,如果一个是string另一个是const char*,返回string
这么办到的?
template<typename T1, typename T2>
struct common_type<T1,T2>
{
typedef decltype(true? declval<T1>() : declval<T2>())type;
}
declval<>是个辅助性trait,依据传入的类型,提供一个rvalue reference
如果?:能够找到一个共通类型,common_type<>就会产出它
细究Type Trait
Type Trait通常被定义于<type_traits>
下面是一些类型判断工具:
is_void<T> //类型void
is_integral<T>//整数类型 bool、char、等
is_floating_point<T>//浮点数类型
is_arithmetic<T>//整数或浮点数类型
is_signed<T>//带正负号的算术类型
is_unsigned<T>//不带正负号的算术类型
is_const<T>//带有const限定符
is_volatile<T>//带有volatile限定符
is_array<T>//寻常的array类型 不是std::array
is_enum<T>//枚举类型
is_union<T>//联合类型
is_class<T>//class/struct类型,但不是union类型
is_function<T>//函数类型
is_reference<T>//左值引用或右值引用
is_lvalue_reference<T>//左值引用
is_rvalue_reference<T>//右值引用
is_pointer<T>//指针类型包括函数指针,不包括指向非静态成员的指针
is_member_pointer<T>//指向非静态成员指针
is_member_object_pointer<T>//指针,指向一个非静态数据成员
is_member_function_pointer<T>//指针,指向一个非静态成员函数
is_fundamental<T>//void,整数型,浮点数或者nullptr_t
is_scalar<T>//整数型、浮点数、枚举、nullptr_t
is_object<T>//任何类型,除了void、function、reference
is_compound<T>//array、enum、union、class、reference、pointer
is_trivial<T>//scalar、trival class或那些
...
针对类类型设计的工具如下:
is_empty<T> //class不带任何成员、virtual成员函数或virtual base class
is_polymorphic<T>//class带有一个virtual成员函数
is_abstract<T>//抽象类即至少有一个纯虚函数
has_virtual_destructor<T>//类带有一个虚析构函数
is_default_constructible<T>//class能够完成默认构造
is_copy_constructible<T>//class能够完成复制构造
is_move_constructible<T>//class能够完成移动构造
is_copy_assignable<T>//class能够完成复制赋值
is_move_assignable<T>//class能够完成移动赋值
is_destructible<T>//class带有可被调用的析构函数(不可以是deleted、Protected、private)
...
用来检验类型关系的Trait
is_same<T1,T2>//检验T1和T2是否是相同类型
is_base_of<T,D>//T是类型D的基类
is_convertible<T,T2>//类型T可转换至类型T2
is_constructible<T,Args...>//可运用类型Args初始化T
....
类型修饰符
下面的trait允许你改动类型
remove_const<T>//对应不带const的类型
remove_volatile<T>//对应不带volatile的类型
remove_cv<T>//对应不带const volatile
add_const<T>//对应之const类型
add_volatile<T>//对应之volatile的类型
add_cv<T>//对应之const volatile类型
make_signed<T>//对应之带正负号的非引用类型
make_unsigned<T>//对应之不带正负号的非引用类型
remove_reference<T>//对应之非引用类型
add_lvalue_reference<T>//对应之左值引用类型
add_rvalue_reference<T>//对应之右值引用类型
remove_pointer<T>//指针所指针的类型
add_pointer<T>//指针类型,指向对应的非引用类类型