C++ traits使用

  1. traits一般是利用編譯器的能力來獲取一些信息。采取的實現(xiàn)方案是模板與模板特化。

  2. 實現(xiàn)細(xì)節(jié):模板類與static成員變量。

----》都是使用模板類來實現(xiàn)的;

----》模板類中都有一個靜態(tài)成員變量,是模板參數(shù)的typedef;

----》這些行為都是編譯器確定的,不是運行期,所以沒有效率問題。

  1. 基礎(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 ; 
  1. 判斷類型是否是某個類型:
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)的時候都可以研究)

  1. 迭代器中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。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容