traits一般是利用編譯器的能力來獲取一些信息。采取的實現(xiàn)方案是模板與模板特化。
實現(xiàn)細(xì)節(jié):模板類與static成員變量。
----》都是使用模板類來實現(xiàn)的;
----》模板類中都有一個靜態(tài)成員變量,是模板參數(shù)的typedef;
----》這些行為都是編譯器確定的,不是運行期,所以沒有效率問題。
- 基礎(chǔ)實現(xiàn)細(xì)節(jié):
(1)消除const屬性,消除volatile屬性:
template< class T >
struct remove_cv {
typedef typename std::remove_volatile<typename std::remove_const<T>::type>::type type;
};
template< class T > struct remove_const { typedef T type; };
template< class T > struct remove_const<const T> { typedef T type; }; //偏特化實現(xiàn);
template< class T > struct remove_volatile { typedef T type; };
template< class T > struct remove_volatile<volatile T> { typedef T type; };
(2)判斷兩個類型是否相同
template<class T, class U>
struct is_same : std::false_type {}; //有一個內(nèi)部靜態(tài)變量value是false;
template<class T>
struct is_same<T, T> : std::true_type {}; //偏特化實現(xiàn)
(3)integral_constant類型:所有traits的基類
template<class T, T v> //參數(shù)是類型T和T類型變量的值;
struct integral_constant {
static constexpr T value = v; //里面有個靜態(tài)成員變量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
};
----》比如我想要類內(nèi)部的static變量是true,即
typedef std::integral_constant<bool, true> true_type ;
- 判斷類型是否是某個類型:
template< class T >
struct is_void : std::is_same<void, typename std::remove_cv<T>::type> {};
類似的實現(xiàn):
判斷是否為空指針類型:
template< class T >
struct is_null_pointer : std::is_same<std::nullptr_t, std::remove_cv_t<T>> {};
判斷是否float類型:
template< class T >
struct is_floating_point
: std::integral_constant<
bool,
std::is_same<float, typename std::remove_cv<T>::type>::value ||
std::is_same<double, typename std::remove_cv<T>::type>::value ||
std::is_same<long double, typename std::remove_cv<T>::type>::value
> {};
左值右值的判斷:
template <class T> struct is_rvalue_reference : std::false_type {};
template <class T> struct is_rvalue_reference<T&&> : std::true_type {};
template<class T> struct is_lvalue_reference : std::false_type {};
template<class T> struct is_lvalue_reference<T&> : std::true_type {};
很多其他is_的判斷比較復(fù)雜,可以需要的時候再研究。(與類型相關(guān)的時候都可以研究)
- 迭代器中traits的使用。
迭代器中定義了一個__type_traits來說明一個類的信息,以決定算法具體采用什么策略來實現(xiàn)。
template <typename type>
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指的是這樣一些數(shù)據(jù)類型:基本數(shù)據(jù)類型、指針、union、數(shù)組、
//構(gòu)造函數(shù)是 trivial 的 struct 或者 class
然后針對C++現(xiàn)有的各種類型,定義__type_traits的全特化版本來實現(xiàn),如:(當(dāng)然沒有實現(xiàn)偏特化的類型都是按上面的定義)
//特化版本
template <>
struct __type_traits<char> {
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 <class T>
struct __type_traits<T*> {
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;
}
算法實現(xiàn)時可以根據(jù)如下方式來判斷到底是否可以使用更簡單的方式來實現(xiàn)算法。
template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator
__uninitialized_copy(InputIterator first, InputIterator last,
ForwardIterator result, T*) {
typedef typename __type_traits<T>::is_POD_type is_POD; //用來判斷是不是POD類型
return __uninitialized_copy_aux(first, last, result, is_POD()); //不是根據(jù)if來判斷調(diào)用哪個邏輯;而是根據(jù)函數(shù)模板參數(shù)的類型來判斷:是true_type還是false_type;
}
根據(jù)是否是是POD類型,分別實現(xiàn):
// Valid if copy construction is equivalent to assignment, and if the
// destructor is trivial.
template <class InputIterator, class ForwardIterator>
inline ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__true_type) {//_true_type說明是POD類型
return copy(first, last, result);//調(diào)用STL算法copy()
}
template <class InputIterator, class ForwardIterator>
ForwardIterator
__uninitialized_copy_aux(InputIterator first, InputIterator last,
ForwardIterator result,
__false_type) {//_false_type說明是non-POD類型,要一個一個的構(gòu)建,無法批量進行
ForwardIterator cur = result;
__STL_TRY {
for ( ; first != last; ++first, ++cur)//一個一個的構(gòu)建
construct(&*cur, *first);
return cur;
}
__STL_UNWIND(destroy(result, cur));
}
從這個角度來看,如果想讓某些函數(shù)運行的更快,需要定義__type_traits的特化版本來告訴編譯器才行。這樣定義的類是更有效率的。
class AAA {};
template <>
struct __type_traits<AAA> { //定義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已經(jīng)有對應(yīng)函數(shù)來確定你的類是否包含這些信息:
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
這些類的實現(xiàn),應(yīng)該是利用編譯器的能力來實現(xiàn)的,此時定義類AAA的時候就不用同時定義traits的特化版本了。
std::is_trivially_default_constructible<AAA> //true_type ,可以利用這個來實現(xiàn)函數(shù)調(diào)用,而不用if來區(qū)分;
is_trivially_default_constructible<AAA> ::value //true or false;
總結(jié)一句,traits通過類模板特化等方式,通過編譯器獲取類型信息。要獲取的信息可以封裝在類內(nèi)部,并定義對應(yīng)的static value,或者對應(yīng)的typedef。