第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;
}
时间: 2024-08-05 04:33:44

第17课 类型萃取(1)_基本的type_traits的相关文章

第19课 类型萃取(3)_类型选择的traits

1. std::conditional (1)原型:template <bool Cond, class T, class F> struct conditional; //根据条件获取T或F类型 template<bool Cond, class T, class F> //泛化 struct conditional { typedef T type; }; template<class T, class F> //偏特化 struct conditional<

C++_模板类与类型萃取技术

在声明变量,函数,和大多数其他类型实体的时候,C++要求我们使用指定的类型.然而,有许多代码,除了类型不同之外,其余部分看起来都是相同的,比如,下面这个例子: bool IsEqual (int left, int right) {     return left == right; } bool IsEqual (const string& left , const string& right) {     return left == right; } void test() {   

头一回发博客,来分享个有关C++类型萃取的编写技巧

废话不多说,上来贴代码最实在,哈哈! 以下代码量有点多,不过这都是在下一手一手敲出来的,小巧好用,把以下代码复制出来,放到相应的hpp文件即可,VS,GCC下均能编译通过 1 #include<iostream> 2 #include "../../traits/traits.hpp" 3 4 5 using namespace std; 6 7 8 int show(char i, int j) 9 { 10 return 1; 11 } 12 13 struct Stu

STL的迭代器和类型萃取

今天就可以把STL库中迭代器的实现,和类型萃取好好整理一下了 迭代器的设计思维是STL的关键所在,在STL的实际运用和泛型思维,迭代器都扮演着十分重要的角色,STL力求把数据容器和算法的概念分开来,于是就有了STL的两大部分,容器(container)和泛型算法(algorithms),泛型算法有很多参数都是迭代器. 举一个栗子!泛型算法find()的实现! 1 template<class InputIterator, class T> 2 InputIterator find(InputI

类型萃取

类型萃取是实现不同类型数据面对同一函数实现不同的操作,它与类封装的区别是:并不用知道所调用的对象是什么类型,类型萃取是编译后知道类型,先实现:而类的封装则是先定义类型,后实现方法. 类型分为基本类型(POD),和自定义类型. 在这里用模板的特化实现其编程思想: 以memcpy为例,当拷贝的是基本类型(POD)时,只用拷贝所传递指针上的数据,如果是string类型,则需要在堆上开辟空间,所传递的指针如果被直接复制,则有可能(vs下的string类型的实现原理是若字符串不长则以数组保存,若字符串过长

c++ 类型萃取(模板类型 运用)

//类型萃取 #pragma once #include<iostream> using namespace std; struct __TrueType//定义类 普通类型(基本类型的) { bool Get() { return true; } }; struct __FalseType//定义类 非基本类型 { bool Get() { return false; } }; template <class _Tp>//模板类 (类型萃取) struct TypeTraits 

通过模板的特化实现 简单的类型萃取 实现memcppy时候对于特殊类型如string类的拷贝。

C++怎样识别一个对象的类型? typeid可以获取到一个类型的名称,但是不能拿来做变量的声明. [POD类型萃取] // // POD: plain old data 平凡类型(无关痛痒的类型)--基本类型 // 指在C++ 中与 C兼容的类型,可以按照 C 的方式处理. //#include<iostream> #include<string> using namespace std; struct __TrueType {  bool Get()  {   return tr

【干货】C++通过模板特化实现类型萃取实例--实现区分基本类型与自定义类型的memcpy

类型萃取是一种常用的编程技巧,其目的是实现不同类型数据面对同一函数实现不同的操作,如STL中cout的实现,它与类封装的区别是,我们并不用知道我们所调用的对象是什么类型,类型萃取是编译器后知道类型,先实现,而类的封装则是先定义类型,后实现方法.在这里我们可以用模板的特化实现其编程思想. 我们以memcpy为例,当我们拷贝的是基本类型时,只用拷贝所传递指针上的数据,如果是string类型呢,我们则需要在堆上开辟空间,所传递的指针如果被直接复制,则有可能(vs下的string类型的实现原理是若字符串

C++ 模板 之 类型萃取 与 容器适配器

类型萃取 在模板这里主要就是对于模板的不同类型的实例化 有不同的方案 这样可以提高效率等 比如 下面的 顺序表 在扩容时的拷贝 对于没有含有指向空间的指针的类 如int 自动使用memcpy() 对于含有指向空间的指针的类 如string 就自动一个一个的赋值 防止浅拷贝导致两个指针指向同一空间 析构两次时出错 类型萃取实现 主要用到了 模板  模板特化 内嵌型别  也可用函数重载 详见Copy() //(1)-------类型萃取 实现顺序表 //----------------------C