TinySTL 之类型萃取 type_traits

2022-5-29 大BUG阅读数:2019评论数:15   C++ 泛型编程 小项目
提示:此篇文章需要了解 C++ 泛型编程的一些概念才能看得懂本文章。

之前对迭代器进行过类型萃取,得到迭代器所指对象类型。同理,我们仍然可以对其他类型的数据进行特性萃取,例如下面的例子,我们对猫和狗能不能被吃的特性进行了萃取,根据萃取结果选择合适的函数

萃取猫的可食用性

代码如下:

                        
#include <iostream>
    // 类
    struct __true_type {
    };
    
    struct __false_type {
    };
    
    // 定义的几个类
    struct Cat { };            // Cat
    
    struct Dog { };            // Dog
    
    struct Fish { };
    
    
    // 类的特性
    template <typename T>
    struct type_traits {
    
    };
    
    template <> 
    struct type_traits<Cat> {
        typedef __false_type isEdible;          // 不可食用
        typedef __true_type isFed;              // 可被饲养
    };
    
    template <> 
    struct type_traits<Dog> {
        typedef __false_type isEdible;          // 不可食用
        typedef __true_type isFed;              // 可被饲养
    };
    
    template <> 
    struct type_traits<Fish> {
        typedef __true_type isEdible;          // 不可食用
        typedef __true_type isFed;              // 可被饲养
    };
    
    
    bool canBeFood(__true_type) {
        std::cout << "Can be Eaten." << std::endl;
        return true;
    }
    
    bool canBeFood(__false_type) {
        std::cout << "Can not be Eaten." << std::endl;
        return false;
    }
    
    
    int main() {
        typedef typename type_traits<Cat>::isEdible category1;    // 萃取猫的可食用性
        canBeFood(category1());
        return 0;
    }
                        
                    

上述代码中的 canBeFood(__true_type)canBeFood(__false_type) 中通过类型来区别函数,并不需要实例化的对象

迭代器类型

C/C++编程:trivial 和 non-trivial

在 C/C++ 的 STL 编程中,针对类型 T,可以大致分为 trivial 和 non-trivial 类型。这个类型是对 T 的四种函数来说的:

  • 构造函数 (ctor)
  • 复制构造函数 (copy)
  • 赋值函数 (assignment)
  • 析构函数 (dtor)

如果上面的函数满足下面 3 条里的某一条:

  1. 显示 (explicit) 定义了这四条函数;
  2. 类里面有非静态非 POD 的数据成员;
  3. 有基类。

那么上面的四种函数是 non-trivial 函数,也就是有意义的函数。因为这些函数里面有了一些必要的操作,例如类成员的初始化、释放内存等操作。 POD 的意思是 Plain Old Data,也就是 C++ 的内建类型或传统的 C 结构体类型。

比如,下面定义的类 T 就是一个 POD 类型的类,而 T1 由于显式定义了构造函数和拥有了一个非 POD 的数据成员 std::string,所以是一个非 POD 类型的类。

                        
// 整个T是POD类型
class T {
    // 没有显式定义ctor/dtor/copy/assignemt 所以都是trivial
    int a; // POD类型
};
    
// 整个T1是非POD类型
class T1 {
    T1() { }           // 显式定义了构造函数,所以是non-trivial ctor
    
    // 没有显式定义ctor/dtor/copy/assignemt 所以都是trivial
    int a;         // POD类型
    std::string b; // 非POD类型
};
                        
                    

那这有什么用处呢?

如果这个类是 trivial ctor/dtor/copy/assignment 函数,我们对这个类进行构造、析构、拷贝和赋值的时候可以采用最有效率的方法,不调用无所事事正真的那些ctor/dtor等,而直接采 用内存操作如 malloc()memcpy()等提高性能,这也是SGI STL内部干的事情。

比如 STL 的 copy 算法最基本的想法是这样的:

                        
// 非POD重载指针数值
template <typename T> 
void copy(T* source, T* destination, int n, __false_type)
{
    // 省略异常处理
    for (; n > 0; n--,source++,destination++)
    {
        // 调用source的复制构造函数
        constructor(source, *destination);
    }
}
    
// POD重载指针数值
template <typename T> 
void copy(T* source, T* destination, int n, __false_type)
{
    // 省略异常处理
    memmove(source, destination, n);
}
                        
                    

然实际的 copy() 比这个复杂多了,有非常多的特化等,这个只是其中一方面而已。

迭代器萃取机

迭代器萃取机用于提取迭代器所代表的数据类型,之前说过,迭代器是对 operator new返回来的指针的一层封装,而有时候可能想要直接使用原生指针来操作数据,所以这里提供原生指针的两种偏特化版本。

针对是否为 trivial 进行 type_traits

这里的 type_traits 使用了类模板偏特化的语法,对常见的类型进行特征萃取,代码位于 type_traits.h 中。


#ifndef TINYSTL_TYPE_TRAITS_H_
#define TINYSTL_TYPE_TRAITS_H_

// 这个头文件用于提取类型信息

namespace TinySTL {

struct __true_type {
};

struct __false_type {
};

template <typename type>
struct __type_traits {
    typedef __true_type this_dummy_must_be_first;
    // 不要移除这个成员,它通知[有能力自动将 __type_traits 特化]
    // 的编译器说,我们现在所看到的这个 __type_traits template 是
    // 特殊的。这是为了确保万一编译器也是用一个名为 __type_traits 而其实
    // 与此处定义无任何关联的 template 时,所有事情将顺利运作。
    typedef __false_type    has_trivial_default_constructor;
    typedef __false_type    has_trivial_copy_constructor;
    typedef __false_type    has_trivial_assignment_operator;
    typedef __false_type    has_trivial_destructor;
    typedef __false_type    is_POD_type;
};

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_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<signed char> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<unsigned char> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<short> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<unsigned short> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<int> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<unsigned int> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<long> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<unsigned long> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<float> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<double> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

template <> struct __type_traits<long double> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

// 注意:以下针对原生指标设计 __type_tratis 偏特化版本
// 原生指标也被视为一种纯量型别
template <typename 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_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

struct __type_traits<char*> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

struct __type_traits<signed char*> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};

struct __type_traits<unsigned char*> {
    typedef __true_type    has_trivial_default_constructor;
    typedef __true_type    has_trivial_copy_constructor;
    typedef __true_type    has_trivial_assignment_operator;
    typedef __true_type    has_trivial_destructor;
    typedef __true_type    is_POD_type;
};


} // namespace TinySTL

#endif
                        

测试

测试的例子如下