第17課 類型萃取(1)_基本的type_traits


1. type_traits類型萃取

(1)type_traits通過定義一些結構體或類並利用模板類特化和偏特化的能力,給類型賦予一些特性,這些特性根據類型的不同而異。在程序設計中可以使用這些traits來判斷一個類型的一些特性,引發C++的函數重載機制,實現同一種操作因類型不同而異的效果。

(2)type_traits提供了豐富的編譯期計算、查詢、判斷、轉換和選擇的幫助類。

(3)type_traits的類型選擇功能,在一定程序上可以消除冗長的switch-cast或if-else的語句。提高代碼可維護性。type_traits的類型判斷功能,在編譯期可以檢查出是否是正確的類型,以能編寫更安全的代碼。

【實例分析】部分類型萃取的實現(類模板)

//#include <iostream>
//using namespace std;
/*********************const/volatile************************/
//remove const
template<typename _Tp>  //泛化
struct remove_const
{
    typedef _Tp   type;
};

template<typename _Tp>
struct remove_const<_Tp const> //特化
{
    typedef _Tp type;
};

//remove_volatile
template<typename _Tp>  //泛化
struct remove_volatile
{
    typedef _Tp  type;
};

template<typename _Tp>
struct remove_volatile<_Tp volatile>  //特化
{
    typedef _Tp  type;
};

//remove_cv
template<typename _Tp>
struct remove_cv
{
    typedef typename
    remove_const<typename remove_volatile<_Tp>::type>::type  type;
};

//add_const
template<typename _Tp>
struct add_const
{
    typedef _Tp const type;
};

/***********************integral_constant*************************/
//常量包裝類型
template <class T, T v>
struct integral_constant
{
    static const T     value = v;
    typedef T          value_type;
    typedef integral_constant<T, v> type;
};

//定義true和false兩個類型
typedef integral_constant<bool, true>  true_type;
typedef integral_constant<bool, false> false_type;

template<typename> //泛化
struct __is_void_helper : public false_type{};

template<>  //特化
struct __is_void_helper<void> : public true_type{};

//is_void
template<typename _Tp>
struct is_void : public __is_void_helper<typename remove_cv<_Tp>::type>::type{};

/***********************integral*************************/
template<typename>    //泛化
struct __is_integral_helper : public false_type{};

template<>  //特化: bool是intergal類型
struct __is_integral_helper<bool> : public true_type{};

template<>  //特化: char是intergal類型
struct __is_integral_helper<char> : public true_type{};

template<>  //特化: int是intergal類型
struct __is_integral_helper<int> : public true_type{};

template<>  //特化: usigned long long是intergal類型
struct __is_integral_helper<unsigned long long> : public true_type{};

//...

//is_integral
template<typename _Tp>
struct is_integral : public __is_integral_helper<typename remove_cv<_Tp>::type>::type{};

//is_const
template <class _Tp> 
struct is_const : public integral_constant<bool, false> {};

template <class _Tp>
struct is_const<_Tp const> : public integral_constant<bool, true> {};

/********************enum/class/union**********************/
//is_enum  注意:__is_enum是編譯器內置類型
template<typename _Tp>
struct is_enum : public integral_constant<bool, __is_enum(_Tp)>{};

//is_union 注意:__is_union是編譯器內置類型
template<typename _Tp>
struct is_union : public integral_constant<bool, __is_union(_Tp)>{};

//is_class 注意:__is_class是編譯器內置類型
template<typename _Tp>
struct is_class : public integral_constant<bool, __is_class(_Tp)>{};

//is_pod: 注意:__is_pod是編譯器內置類型
template<typename _Tp>
struct is_pod : public integral_constant<bool, __is_pod(_Tp)>{};

int main()
{
    return 0;
}

2. 類型判斷

(1)基本類型(類模板判斷T是否是相應的類型

  ①is_void、is_integral、is_array、is_floating_point(浮點)、 is_pointer

  ②is_enum、is_union、is_class

  ③is_lvalue_reference、is_rvalue_reference

  ④is_function、is_member_object_pointer(成員對象指針)、is_member_function_pointer(成員函數指針)

(2)復合類型(類模板

  ①is_fundamental:是否是整型、浮點、void或null_ptr類型。

  ②is_arithemetic:是否是整型和浮點類型

  ③is_scalar:是否是arithemetic、enumeration、pointer、pointer to member或std::nullptr_t類型。

  ④is_object:是否為對象類型(不是函數、引用或void)

  ⑤is_compound:是否非fundamental類型構造的

  ⑥is_reference:是否為引用(含左值引用和右值引用)

  ⑦is_member_pointer:是否是成員指針(即非靜態成員對象或函數的指針)

(3)類型的屬性

  ①is_const、is_volatile、is_literal_type、is_signed、is_unsigned。

  ②is_trivial、is_trivially_copyable、is_standart_layout(標准內存布局,一般用於跨語言的兼容)、is_pod、is_empty(空類)

  ③is_polymorphic(是否有虛函數)、is_abstract(是否是抽象類)

3. 兩個類型之間的關系

(1)is_same<T, U>: T和U的類型是否相同

(2)is_base_of<Base, Derived>:Base是否為Derived類型的基類

(3)is_convertible<From, To>:From是否能轉為To模板參數類型

【編程實驗】基本type_traits和判斷兩個類型之間的關系

#include <iostream>

using namespace std;

class Parent{};
class Child : public Parent{}; //class Child : Parent{},為private繼承
class Alone{};

int main()
{
    cout << std::boolalpha; //以下的0、1按false和true格式輸出
    
    /*基本的type_traits用法*/
    cout << is_const<int>::value << endl;         //false
    cout << is_const<const int>::value << endl;   //true
    cout << is_const<const int&>::value << endl;  //false
    cout << is_const<const int*>::value << endl;  //false
    cout << is_const<int* const>::value << endl;  //true
    
    /*is_same用法*/
    cout << is_same<int, int>::value << endl;         //true
    cout << is_same<int, unsigned int>::value << endl;//false
    cout << is_same<int, signed int>:: value << endl; //true
    
    /*is_base_of*/
    cout << is_base_of<Parent, Child>:: value << endl; //true
    cout << is_base_of<Child, Parent>:: value << endl; //false
    cout << is_base_of<Parent, Alone>:: value << endl; //false
    
    /*is_convertible<From, To>用法:判斷From類型是否可以轉為To類型*/
    cout << is_convertible<Parent*, Child*>:: value << endl; //false
    cout << is_convertible<Child*, Parent*>:: value << endl; //true
    cout << is_convertible<Parent*, Alone*>:: value << endl; //false    
    return 0;
}

4. 類型轉換traits

(1)const-volatile限定符

  ①remove_cv<T>、remove_const<T>、remove_volatile<T>

  ②add_cv<T>、add_const<T>、add_volatile<T>

(2)引用: remove_reference<T>、add_lvalue_reference<T>、add_rlvalue_reference。

(3)指針: remove_pointer<T>、add_pointer<T>

(4)數組:remove_extent<T>移除數組頂層維度、remove_all_extents<T>移除所有維度。

(5)其它

  ①decay<T>類型退化,主要用移除引用、cv符及為函數或數組添加指針。其轉換規則如下。

    A.先移除T的類型引用,得到類型U,U定義為remove_reference<T>::type

    B.如果is_array<U>::value為true,最終轉換為remove_extent<U>::type*

    C.否則,如果is_function<U>::value為true,轉換為add_pointer<U>::type

    D.否則,轉換為remove_cv<U>::type

  ②common_type<T1, T2, T3…>:獲取公共類型

【編程實驗】類型轉換traits

#include <iostream>
#include <memory>

using namespace std;
//類型轉換type_traits

//根據模板參數類創建對象時,要注意移除cv和引用
template<typename T>
class Test
{
    //typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type U;  //移除可能的引用和cv    
    //以上的等價寫法
    typedef typename std::decay<T>::type U; //先移除T的引用,再移除cv符,
    
    std::unique_ptr<U> m_ptr; //m_ptr智能指針
    
public:
    Test(): m_ptr(new U){} //創建智能指針時,需要獲取T的原始類型
    
    typename std::add_lvalue_reference<U>::type //返回值類型,添加左值引用
    get() const
    {
        return *m_ptr.get();
    }
};

//利用std::decay保存函數指針
template<typename T>
class Sample
{
    using FnType = typename std::decay<T>::type; //為函數添加指針
    FnType m_fn;
public:
    Sample(T& f) : m_fn(f){};
    
    void run()
    {
        m_fn();
    }
};

void func()
{
    cout <<"void func()" << endl;
}

int main()
{
    cout << std::boolalpha; //以下的0、1按false和true格式輸出
    
    //添加和移除const、reference
    cout <<is_same<const int, add_const<int>::type>::value << endl;         //true
    cout <<is_same<int, remove_const<const int>::type>::value << endl;      //true
    cout <<is_same<int&, add_lvalue_reference<int>::type>::value << endl;   //true
    cout <<is_same<int&&,add_rvalue_reference<int>::type>::value << endl;   //true
    cout <<is_same<int, remove_reference<int&>::type>::value << endl;       //true
    cout <<is_same<int, remove_reference<int&&>::type>::value << endl;      //true

      cout <<is_same<int*, add_pointer<int>::type>::value << endl;    //true

    //移除數組頂層維度
    cout <<is_same<int, remove_extent<int[]>::type>::value << endl;             //true     
    cout <<is_same<int[2], remove_extent<int[][2]>::type>::value << endl;       //true     
    cout <<is_same<int[2][3], remove_extent<int[][2][3]>::type>::value << endl; //true 
    cout <<is_same<int, remove_all_extents<int[][2][3]>::type>::value << endl;  //true,移除所有維度
    
    //取公共類型
    typedef common_type<unsigned char, short, int>::type NumericType;
    cout <<is_same<int, NumericType>::value << endl;   //true
    
    //測試Test類
    Test<const int&> t; //T類型故意傳入帶cv和引用,Test類部在創建對象時,需去除這些屬性
    int a = t.get();
    cout << a << endl;
    
    //std::decay
    cout <<is_same<int, decay<int>::type>::value << endl;              //true
    cout <<is_same<int, decay<int&&>::type>::value << endl;            //true,移除引用
    cout <<is_same<int, decay<const int&>::type>::value << endl;       //true,移除cv和引用
    cout <<is_same<int*, decay<int[2]>::type>::value << endl;          //true,移除數組頂層維度
    cout <<is_same<int(*)(int), decay<int(int)>::type>::value << endl; //true,將函數變為函數指針
    
    Sample<decltype(func)> s(func);
    s.run();  //void func();
    
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM