类型萃取

类型萃取 - 从零开始教学

什么是类型萃取?

类型萃取(Type Traits)是 C++ 模板元编程的核心技术,用于在编译期获取类型的信息或转换类型。

第一章:最基础的类型萃取

1.1 判断类型是否相同

// 最基础版本 - C++03 风格
template<typename T, typename U>
struct is_same {
    static const bool value = false;
};

// 特化版本:当两个类型相同时
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;
};

// 特化版本:当条件为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 类型,如果失败则选择这个函数
    template<typename U>
    static char test(...);

    // 如果能成功获取 pointer 类型,则选择这个函数
    template<typename U>
    static int test(typename U::pointer* = 0);

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

// 更现代的 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 实际应用:__pointer 的实现

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

// 特化版本:如果 T 没有 pointer 成员,使用默认指针
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*
}

第四章:实际项目中的应用

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_; }
    // ... 其他成员函数
};

4.2 容器中的类型萃取

// 简化的 vector 实现
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:
    // ... 构造函数、析构函数等
    pointer data() { return data_; }
    const_pointer data() const { return data_; }
};

第五章:从零实现完整的类型萃取库

5.1 基础类型判断

// 类型分类
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 类型转换

// 添加 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;
};

第六章:现代 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 {};

第七章:实战练习

7.1 实现一个完整的类型萃取工具

// 综合示例:实现一个智能的指针包装器
namespace my_type_traits {

// 基础类型萃取
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;
}

总结

类型萃取的核心思想:

  1. 编译时计算:所有操作都在编译期完成
  2. 模板特化:通过特化实现条件逻辑
  3. SFINAE:利用编译错误处理实现类型检测
  4. 零开销:运行时没有任何额外开销

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

参考资料

  • 《C++ Templates: The Complete Guide》
  • 《C++ Template Metaprogramming》
  • LLVM libc++ 源码
  • C++ 标准库 <type_traits> 头文件
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容