模板的类型萃取

本文介绍了一种称为类型萃取的技术,该技术主要用于判断变量是否为POD类型,从而在复制不同类型的数据时选择最合适的操作方式。对于内置类型,使用memcpy函数可以显著提高效率;而对于自定义类型,则需要调用赋值语句来避免浅拷贝带来的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

功能

  类型萃取,在STL中用到的比较多,用于判断一个变量是否为POD类型.

  简述来说可以用来判断出某个变量是内置类型还是自定义类型.

  通过类型萃取,萃取到变量类型,对不同变量进行不同处理,可以提升程序效率(下面有具体讲解).

应用场景

  比如我们实现顺序表,在对顺序表进行扩容时,就靠重新开辟内存、拷贝对象.

  拷贝对象时,就有两种情况:一种是类型,比如int char…;还有一种是自定义类型,Data类、String类.

  对于内置类型,我们可以通过memset,来进行赋值.(扩展,浅拷贝相关的类也可以通过memset赋值)

  而对于自定义类型,大多数深拷贝的对象来说,我们必须通过调用赋值语句来赋值.

  因此,我们通常在拷贝对象时,为了不出现错误,都用赋值语句来赋值.

  而我们如果有一种方法/机制可以判断POD类型或者非POD类型.

  对于POD类型用memset函数,对于非POD用赋值,这样就能提高程序的效率  


最大的功能

类型萃取的最大功能就是提高了程序的效率.例如下面的代码,就会出现错误。

template <class T>
void Copy( T* dst, T* src,size_t size)//这里的size是数据个数
{
    memcpy(dst, src, sizeof(T)*size);
}

如果T类型是int,char,float ...这些内置类型,使用memcpy()函数拷贝没有问题,并且使用memcpy()更快,比一个一个赋值赋值语句快很多,但是如果T类型是string这些自定义的类型(有自己的构造函数),使用memcpy()就是出现错误,string通过memcpy()拷贝后,程序就会蹦,因为mencpy()函数是浅拷贝,他只是把string实例化的这个对象的内存拷贝过去,_str浅拷贝过去,当出了这个作用域后,string调用自己的析构函数,因为一块地址被两个指针所指向,析构第二次时就会蹦。
那么解决这个问题的办法就是专门为string写一个拷贝函数,但是这样没有普遍性,写一个类专门写一个函数会很麻烦,模版的类型萃取就很好的解决了这个办法,提高了运算效率,当对象是内置类型是使用mencpy(),当对象是自定义类型时,使用自己写的函数。下面是实现模版的类型萃取的代码。

类型萃取具体实现代码
#pragma once
#include<iostream>
#include<string>


using namespace std;

//  默认是内置类型,char,int,double....
struct True_Type
{
    bool Get_Type()
    {
        return true;
    }
};

//不是内置类型,比如自己定义的类,在项目中具体用到类型时,可以再自己定义
struct False_Type
{
    bool Get_Type()
    {
        return false;
    }
};

template <class T>
struct Type_Extraction
{
    typedef False_Type Is_Pod_Type;   //Is_Pod_Type意思是平凡类型,
};                                    //这里默认 Is_Pod_Type 就是 False_Type,因为在下面的偏特化中会
                                      // typedef True_Type Is_Pod_Type.就会改变 Is_Pod_Type


template<>
struct Type_Extraction<int>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<char>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<double >
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<float>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<long long>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<bool>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<unsigned char>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<short>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<unsigned short>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<unsigned int>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<long>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<unsigned long>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<unsigned long long>
{
    typedef True_Type Is_Pod_Type;
};

template<>
struct Type_Extraction<long double>
{
    typedef True_Type Is_Pod_Type;
};

template <class T>
struct Type_Extraction<T*>
{
    typedef True_Type Is_Pod_Type;
};

template <class T>
struct Type_Extraction<const T*>
{
    typedef True_Type Is_Pod_Type;
};




            //上面都是内置类型,因为原来默认  Is_Pod_Type  是False_Type    ,
            //所以上面的模版偏特化都把 Is_Pod_Type 重命名为 True_Tpye


//
//使用参数(类型)推导到相应的函数模版
//



//内置类型,使用memcpy并不会导致错误。
template <class T>
void Copy( T* dst, T* src,size_t size,True_Type)//这里的size是数据个数
{
    cout << "True_Type" << endl;
    memcpy(dst, src, sizeof(T)*size);//memcpy 参数的size 是字节数
}


//特殊类型,比如string,new时需要调用自己的构造函数时,需要自己实现拷贝,不能使用memcpy,会导致错误。

//第一种方法,根据参数类型自己选择,因为参数有False_Type,编译器会自己挑选最匹配的
template <class T>
void Copy( T* dst, T* src, size_t size, False_Type)
{
    cout << "False_Type" << endl;
    for (int i = 0; i < (int)size; i++)
    {
        dst[i] = src[i];
    }
}

//第二种,根据萃取判断类型中的 Get_Type()函数的返回值判断是否是平凡类型(Is_Pod_Type)

template <class T>
void Copy( T* dst, T*src, size_t size)
{
    if (Type_Extraction<T>::Is_Pod_Type().Get_Type())//如果 Is_Pod_Type 是True_Type ,Get_Type()返回值就是true.
    {
        memcpy(dst, src, sizeof(T)*size);//memcpy 参数的size 是字节数
    }
    else
    {
        for (int i = 0; i < (int)size; i++)
        {
            dst[i] = src[i];
        }
    }
}


#include<iostream>
#include<string>
#include"test.h"


using namespace std;


int main()
{

    string s1[10] = { "ad", "adad", "adadad" };
    string s2[10] = { "adadasd", "adaadadd", "adadaadadd" };
    Copy(s1, s2, 5, Type_Extraction<string>::Is_Pod_Type());
    cout << s1[1] << endl;

    int a[10] = { 1, 2, 4, 5, 6, 7, 8 };
    int b[10] = { 9, 8, 8, 7, 6, 5, };
    Copy(a, b, 5);
    cout << a[0] << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值