類型萃取

類型萃取 - 從零開始教學(xué)

什么是類型萃?。?/h2>

類型萃?。═ype Traits)是 C++ 模板元編程的核心技術(shù),用于在編譯期獲取類型的信息或轉(zhuǎn)換類型。

第一章:最基礎(chǔ)的類型萃取

1.1 判斷類型是否相同

// 最基礎(chǔ)版本 - C++03 風(fēng)格
template<typename T, typename U>
struct is_same {
    static const bool value = false;
};

// 特化版本:當(dāng)兩個類型相同時
template<typename T>
struct is_same<T, T> {
    static const bool value = true;
};

// 使用示例
#include <iostream>
int main() {
    std::cout << is_same<int, int>::value << std::endl;      // 輸出:1 (true)
    std::cout << is_same<int, double>::value << std::endl;   // 輸出:0 (false)
}

1.2 移除引用

// 主模板:處理非引用類型
template<typename T>
struct remove_reference {
    typedef T type;
};

// 特化版本:處理左值引用
template<typename T>
struct remove_reference<T&> {
    typedef T type;
};

// 特化版本:處理右值引用(C++11)
template<typename T>
struct remove_reference<T&&> {
    typedef T type;
};

// 使用示例
#include <iostream>
int main() {
    remove_reference<int>::type a;        // int
    remove_reference<int&>::type b;       // int
    remove_reference<int&&>::type c;      // int
}

第二章:條件類型選擇

2.1 條件類型選擇器

// 條件選擇模板
template<bool Condition, typename TrueType, typename FalseType>
struct conditional {
    typedef FalseType type;
};

// 特化版本:當(dāng)條件為true時
template<typename TrueType, typename FalseType>
struct conditional<true, TrueType, FalseType> {
    typedef TrueType type;
};

// 使用示例
#include <iostream>
template<typename T>
void print_type() {
    typedef typename conditional<sizeof(T) > 4, long, short>::type SelectType;
    std::cout << "Selected type size: " << sizeof(SelectType) << std::endl;
}

int main() {
    print_type<double>();   // 如果 sizeof(double) > 4,選擇 long
    print_type<char>();     // 如果 sizeof(char) > 4,選擇 short
}

第三章:檢測成員是否存在(SFINAE)

3.1 檢測類型是否有某個成員

// C++03 版本:檢測是否有 pointer 成員
template<typename T>
struct has_pointer {
private:
    // 嘗試獲取 pointer 類型,如果失敗則選擇這個函數(shù)
    template<typename U>
    static char test(...);

    // 如果能成功獲取 pointer 類型,則選擇這個函數(shù)
    template<typename U>
    static int test(typename U::pointer* = 0);

public:
    static const bool value = sizeof(test<T>(0)) == sizeof(int);
};

// 更現(xiàn)代的 C++11 版本
template<typename, typename = void>
struct has_pointer : std::false_type {};

template<typename T>
struct has_pointer<T, std::void_t<typename T::pointer>> : std::true_type {};

3.2 實際應(yīng)用:__pointer 的實現(xiàn)

// 主模板:如果 T 有 pointer 成員,使用它
template<typename T, bool HasPointer = has_pointer<T>::value>
struct get_pointer {
    typedef typename T::pointer type;
};

// 特化版本:如果 T 沒有 pointer 成員,使用默認(rèn)指針
template<typename T>
struct get_pointer<T, false> {
    typedef T* type;
};

// 使用示例
struct MyAllocator {
    typedef int* pointer;  // 自定義指針類型
};

struct DefaultAllocator {
    // 沒有 pointer 成員
};

int main() {
    get_pointer<MyAllocator>::type p1;      // int*
    get_pointer<DefaultAllocator>::type p2; // DefaultAllocator*
}

第四章:實際項目中的應(yīng)用

4.1 自定義智能指針的指針類型選擇

// 智能指針模板
template<typename T, typename Deleter = std::default_delete<T>>
class my_unique_ptr {
private:
    // 使用類型萃取選擇指針類型
    typedef typename get_pointer<Deleter>::type pointer;

    pointer ptr_;
    Deleter deleter_;

public:
    explicit my_unique_ptr(pointer p = nullptr) : ptr_(p) {}

    ~my_unique_ptr() {
        if (ptr_) {
            deleter_(ptr_);
        }
    }

    pointer get() const { return ptr_; }
    // ... 其他成員函數(shù)
};

4.2 容器中的類型萃取

// 簡化的 vector 實現(xiàn)
template<typename T, typename Allocator = std::allocator<T>>
class my_vector {
private:
    // 萃取各種類型
    typedef typename Allocator::value_type value_type;
    typedef typename get_pointer<Allocator>::type pointer;
    typedef typename get_pointer<Allocator>::type const_pointer;

    pointer data_;
    size_t size_;
    size_t capacity_;

public:
    // ... 構(gòu)造函數(shù)、析構(gòu)函數(shù)等
    pointer data() { return data_; }
    const_pointer data() const { return data_; }
};

第五章:從零實現(xiàn)完整的類型萃取庫

5.1 基礎(chǔ)類型判斷

// 類型分類
template<typename T>
struct type_traits {
    static const bool is_pointer = false;
    static const bool is_reference = false;
    static const bool is_const = false;
    static const bool is_void = false;
};

// 特化版本
template<typename T>
struct type_traits<T*> {
    static const bool is_pointer = true;
    static const bool is_reference = false;
    static const bool is_const = false;
    static const bool is_void = false;
};

template<typename T>
struct type_traits<T&> {
    static const bool is_pointer = false;
    static const bool is_reference = true;
    static const bool is_const = false;
    static const bool is_void = false;
};

template<typename T>
struct type_traits<const T> {
    static const bool is_pointer = type_traits<T>::is_pointer;
    static const bool is_reference = type_traits<T>::is_reference;
    static const bool is_const = true;
    static const bool is_void = type_traits<T>::is_void;
};

template<>
struct type_traits<void> {
    static const bool is_pointer = false;
    static const bool is_reference = false;
    static const bool is_const = false;
    static const bool is_void = true;
};

5.2 類型轉(zhuǎn)換

// 添加 const
template<typename T>
struct add_const {
    typedef const T type;
};

// 移除 const
template<typename T>
struct remove_const {
    typedef T type;
};

template<typename T>
struct remove_const<const T> {
    typedef T type;
};

// 添加指針
template<typename T>
struct add_pointer {
    typedef T* type;
};

// 移除指針
template<typename T>
struct remove_pointer {
    typedef T type;
};

template<typename T>
struct remove_pointer<T*> {
    typedef T type;
};

template<typename T>
struct remove_pointer<T* const> {
    typedef T type;
};

第六章:現(xiàn)代 C++ 中的簡化

6.1 C++11 簡化版本

// 使用別名模板簡化
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;

template<typename T>
using conditional_t = typename conditional<B, T, F>::type;

template<bool B, typename T, typename F>
using conditional_t = typename conditional<B, T, F>::type;

6.2 C++17 的 std::void_t

template<typename...>
using void_t = void;

// 簡化成員檢測
template<typename T, typename = void>
struct has_value_type : std::false_type {};

template<typename T>
struct has_value_type<T, std::void_t<typename T::value_type>> : std::true_type {};

第七章:實戰(zhàn)練習(xí)

7.1 實現(xiàn)一個完整的類型萃取工具

// 綜合示例:實現(xiàn)一個智能的指針包裝器
namespace my_type_traits {

// 基礎(chǔ)類型萃取
template<typename T> struct is_const : std::false_type {};
template<typename T> struct is_const<const T> : std::true_type {};

template<typename T> struct is_pointer : std::false_type {};
template<typename T> struct is_pointer<T*> : std::true_type {};

// 移除引用
template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };
template<typename T> struct remove_reference<T&&> { typedef T type; };

// 條件選擇
template<bool B, typename T, typename F>
struct conditional { typedef F type; };

template<typename T, typename F>
struct conditional<true, T, F> { typedef T type; };

// 成員檢測
template<typename T>
struct has_pointer_member {
private:
    template<typename U> static std::true_type test(typename U::pointer*);
    template<typename> static std::false_type test(...);
public:
    static constexpr bool value = decltype(test<T>(nullptr))::value;
};

// 智能指針類型選擇
template<typename T, typename Deleter>
struct smart_pointer_type {
    typedef typename conditional<
        has_pointer_member<Deleter>::value,
        typename Deleter::pointer,
        T*
    >::type type;
};

} // namespace my_type_traits

// 使用示例
int main() {
    // 測試類型萃取
    static_assert(my_type_traits::is_const<const int>::value, "Should be const");
    static_assert(!my_type_traits::is_const<int>::value, "Should not be const");

    // 測試智能指針類型選擇
    struct MyDeleter {
        typedef int* pointer;
    };

    typedef my_type_traits::smart_pointer_type<int, MyDeleter>::type ptr_type1; // int*
    typedef my_type_traits::smart_pointer_type<int, std::default_delete<int>>::type ptr_type2; // int*

    return 0;
}

總結(jié)

類型萃取的核心思想:

  1. 編譯時計算:所有操作都在編譯期完成
  2. 模板特化:通過特化實現(xiàn)條件邏輯
  3. SFINAE:利用編譯錯誤處理實現(xiàn)類型檢測
  4. 零開銷:運(yùn)行時沒有任何額外開銷

掌握類型萃取,你就掌握了 C++ 模板元編程的精髓!

參考資料

  • 《C++ Templates: The Complete Guide》
  • 《C++ Template Metaprogramming》
  • LLVM libc++ 源碼
  • C++ 標(biāo)準(zhǔn)庫 <type_traits> 頭文件
?著作權(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)容