一. c++ traits定义
type_traits使用模板技术来萃取类型(包含自定义类型和内置类型)的某些特性,用以判断该类型是否含有某些特性,从而在泛型算法中来对该类型进行特殊的处理用来提高效率或者其他。
通过type_traits可以实现在编译期计算、查询、判断、转换和选择,增强了泛型编程的能力,也增强了程序的弹性,使得我们在编译期就能做到优化改进甚至排错,能进一步提高代码质量。
二.几个栗子
http://www.cplusplus.com/reference/type_traits/?kw=type_traits
cplusplusreference网站列举出了一大堆。这里举几个栗子说明type_traits是怎么实现的(vs2019 stl源码)。
integral_constant
template <class _Ty, _Ty _Val>
struct integral_constant {
// static 编译期常量。static是为了保证value变量只有一个。并且constexpr表明value必须是一个编译期常量。
static constexpr _Ty value = _Val;
using value_type = _Ty;
using type = integral_constant;
constexpr operator value_type() const noexcept {
return value;
}
_NODISCARD constexpr value_type operator()() const noexcept {
return value;
}
};
注意上面定义的strct intergral_constant模板中
static constexpr _Ty value = _Val;
如果没有constexpr修饰就会报编译错误:a static data member with an in-class initializer must have non-volatile const integral type
只能在其声明中初始化整数类型的常量静态成员,如果是非整数类型就会有问题。
true_type和false_type
template <bool _Val>
using bool_constant = integral_constant<bool, _Val>;
using true_type = bool_constant<true>;
using false_type = bool_constant<false>;
is_integral
template <class>
_INLINE_VAR constexpr bool _Is_integral = false; // determine whether cv-unqualified type argument is integral
// 模板显式具体化(注意区分显式具体化和显式实例化)
template <>
_INLINE_VAR constexpr bool _Is_integral<bool> = true;
template <>
_INLINE_VAR constexpr bool _Is_integral<char> = true;
template <>
_INLINE_VAR constexpr bool _Is_integral<int> = true;
template <>
_INLINE_VAR constexpr bool _Is_integral<unsigned int> = true;
// ...这里只贴出以上四种特化版本,省略其它各种可以识别为整型的特化版本
template <class _Ty>
_INLINE_VAR constexpr bool is_integral_v = _Is_integral<remove_cv_t<_Ty>>; // determine whether _Ty is integral
template <class _Ty>
struct is_integral : bool_constant<is_integral_v<_Ty>> {};
由源码可以看出,std::is_integral通过实现各种整型类型的特化版本,来实现识别整型类型。
使用中通过识别std::is_integral::value为true/false。
is_reference 特化出左值引用和右值引用的版本
template <class>
_INLINE_VAR constexpr bool is_reference_v = false; // determine whether type argument is a reference
template <class _Ty>
_INLINE_VAR constexpr bool is_reference_v<_Ty&> = true;
template <class _Ty>
_INLINE_VAR constexpr bool is_reference_v<_Ty&&> = true;
template <class _Ty>
struct is_reference : bool_constant<is_reference_v<_Ty>> {};
is_const
template <class>
_INLINE_VAR constexpr bool is_const_v = false; // determine whether type argument is const qualified
template <class _Ty>
_INLINE_VAR constexpr bool is_const_v<const _Ty> = true;
template <class _Ty>
struct is_const : bool_constant<is_const_v<_Ty>> {};
is_same
template <class, class>
_INLINE_VAR constexpr bool is_same_v = false; // determine whether arguments are the same type
template <class _Ty>
_INLINE_VAR constexpr bool is_same_v<_Ty, _Ty> = true;
template <class _Ty1, class _Ty2>
struct is_same : bool_constant<is_same_v<_Ty1, _Ty2>> {};
enable_if
template <bool _Test, class _Ty = void> //泛化版本
struct enable_if {}; // no member "type" when !_Test
template <class _Ty> //偏特化版本(部分具体化)
struct enable_if<true, _Ty> { // type is _Ty for _Test
using type = _Ty;
};
满足条件时类型有效。从源码可知只有当第一个模板参数为true时,type才有效。
否则访问type编译出错。通常做一些编译期的类型检查。
第二个参数有默认值void,所以如果不指定第二个参数,只是做check。
如果要用到type,需要指定第二个模板参数。
例如:
enable_if<true>::type // void
enable_if<true, int>::type // int