traits一般是利用编译器的能力来获取一些信息。采取的实现方案是模板与模板特化。
实现细节:模板类与static成员变量。
----》都是使用模板类来实现的;
----》模板类中都有一个静态成员变量,是模板参数的typedef;
----》这些行为都是编译器确定的,不是运行期,所以没有效率问题。
- 基础实现细节:
(1)消除const属性,消除volatile属性:
template< class T >
struct remove_cv {
typedef typename std::remove_volatile::type>::type type;
};
template< class T > struct remove_const { typedef T type; };
template< class T > struct remove_const { typedef T type; }; //偏特化实现;
template< class T > struct remove_volatile { typedef T type; };
template< class T > struct remove_volatile { typedef T type; };
(2)判断两个类型是否相同
template
struct is_same : std::false_type {}; //有一个内部静态变量value是false;
template
struct is_same : std::true_type {}; //偏特化实现
(3)integral_constant类型:所有traits的基类
template //参数是类型T和T类型变量的值;
struct integral_constant {
static constexpr T value = v; //里面有个静态成员变量T value = v;
typedef T value_type;
typedef integral_constant type; // using injected-class-name
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; } //since c++14
};
----》比如我想要类内部的static变量是true,即
typedef std::integral_constant true_type ;
- 判断类型是否是某个类型:
template< class T >
struct is_void : std::is_same::type> {};
类似的实现:
判断是否为空指针类型:
template< class T >
struct is_null_pointer : std::is_same> {};
判断是否float类型:
template< class T >
struct is_floating_point
: std::integral_constant<
bool,
std::is_same::type>::value ||
std::is_same::type>::value ||
std::is_same::type>::value
> {};
左值右值的判断:
template struct is_rvalue_reference : std::false_type {};
template struct is_rvalue_reference : std::true_type {};
template struct is_lvalue_reference : std::false_type {};
template struct is_lvalue_reference : std::true_type {};
很多其他is_的判断比较复杂,可以需要的时候再研究。(与类型相关的时候都可以研究)
- 迭代器中traits的使用。
迭代器中定义了一个__type_traits来说明一个类的信息,以决定算法具体采用什么策略来实现。
template
struct __type_traits {
//不要移除
typedef __true_type this_dummy_member_must_be_first;
//trivial指无意义的
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_constructor;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
//POD指的是这样一些数据类型:基本数据类型、指针、union、数组、
//构造函数是 trivial 的 struct 或者 class
然后针对C++现有的各种类型,定义__type_traits的全特化版本来实现,如:(当然没有实现偏特化的类型都是按上面的定义)
//特化版本
template <>
struct __type_traits {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_constructor;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
template
struct __type_traits {
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_constructor;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
}
算法实现时可以根据如下方式来判断到底是否可以使用更简单的方式来实现算法。
template
inline ForwardIterator
__uninitialized_copy(InputIterator first, InputIterator last,
ForwardIterator result, T*) {
typedef typename __type_traits::is_POD_type is_POD; //用来判断是不是POD类型
return __uninitialized_copy_aux(first, last, result, is_POD()); //不是根据if来判断调用哪个逻辑;而是根据函数模板参数的类型来判断:是true_type还是false_type;
}
根据是否是是POD类型,分别实现:
// Valid if copy construction is equivalent to assignment, and if the
// destructor is trivial.
template
inline ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__true_type) {//_true_type说明是POD类型
return copy(first, last, result);//调用STL算法copy()
}
template
ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__false_type) {//_false_type说明是non-POD类型,要一个一个的构建,无法批量进行
ForwardIterator cur = result;
__STL_TRY {
for ( ; first != last; ++first, ++cur)//一个一个的构建
construct(&*cur, *first);
return cur;
}
__STL_UNWIND(destroy(result, cur));
}
从这个角度来看,如果想让某些函数运行的更快,需要定义__type_traits的特化版本来告诉编译器才行。这样定义的类是更有效率的。
class AAA {};
template <>
struct __type_traits { //定义AAA之后,同时定义这个。
typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
typedef __true_type has_trivial_assignment_constructor;
typedef __true_type has_trivial_destructor;
typedef __true_type is_POD_type;
};
但C++11已经有对应函数来确定你的类是否包含这些信息:
is_constructible
is_trivially_constructible
is_nothrow_constructible
checks if a type has a constructor for specific arguments
(class template)
is_default_constructible
is_trivially_default_constructible
is_nothrow_default_constructible
checks if a type has a default constructor
(class template)
is_copy_constructible
is_trivially_copy_constructible
is_nothrow_copy_constructible
//更多可以参考:cppreference.com 中的type_traits
这些类的实现,应该是利用编译器的能力来实现的,此时定义类AAA的时候就不用同时定义traits的特化版本了。
std::is_trivially_default_constructible //true_type ,可以利用这个来实现函数调用,而不用if来区分;
is_trivially_default_constructible ::value //true or false;
总结一句,traits通过类模板特化等方式,通过编译器获取类型信息。要获取的信息可以封装在类内部,并定义对应的static value,或者对应的typedef。