類型萃取 - 從零開始教學(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é)
類型萃取的核心思想:
- 編譯時計算:所有操作都在編譯期完成
- 模板特化:通過特化實現(xiàn)條件邏輯
- SFINAE:利用編譯錯誤處理實現(xiàn)類型檢測
- 零開銷:運(yùn)行時沒有任何額外開銷
掌握類型萃取,你就掌握了 C++ 模板元編程的精髓!
參考資料
- 《C++ Templates: The Complete Guide》
- 《C++ Template Metaprogramming》
- LLVM libc++ 源碼
- C++ 標(biāo)準(zhǔn)庫
<type_traits>頭文件