欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++类型萃取

程序员文章站 2022-06-10 13:48:47
...
  在利用模板来实现容器vector的时候,由于是泛型编程,所以参数类型是可以说是任意的,而当我们希望实现对一块连续空间进行拷贝的时候,有两种实现方式,一种是memcpy函数实现,另一种则是通过for循环一个一个赋值。
   memcpy是一种很高效的方式,但是,当拷贝自定义类型时就会牵扯到深浅拷贝的问题,因为memcpy的实现方式是浅拷贝,在释放内存的时候往往会因为多次释放同一块内存而导致程序崩溃。
   所以当拷贝自定义类型时就需要采用for循环一个一个赋值(赋值运算符重载的时候的实现方式是深拷贝)的方式来实现拷贝了。可能有人会有疑问,为什么不直接选择将所有的拷贝方式都用for循环来实现呢。因为for循环的效率很低。而memcpy的效率高,而且当T为内置类型时,memcpy不仅不会出错而且效率还很高。
   自然而然地,就想到利用一个方法能够实现在拷贝内置类型的时候使用memcpy,拷贝自定义类型的时候使用for循环。这样就既保证了程序既不会出错又高效。接下来就来实现这种方法-------**类型萃取**。

看代码:

struct TrueType
{
    bool Get()
    {
        return true;
    }
};

struct FalseType
{
    bool Get()
    {
        return false;
    }
};

首先定义了TrueType和FalseType两个类,注意这两个类都是用struct关键字声明的,这是为了让类里边的成员默认为公有的,用class关键字来声明也可以,只要在类成员里边加将其声明为公有的就行了。

template<typename Ty>
struct TypeTraits
{
    typedef FalseType IsPODType;
};

这段代码声明了一个类模板,在类模板里边就只做一件事情,将FalseType重命名为 IsPODType 。在这个模板类中将所有的类型假定都为自定义类型。说明: IsPODType 是在类TypeTraits里边声明的,也就相当于类 TypeTraits 的一个成员类型,之后使用它的时候需要加 TypeTraits::作用域,记住,IsPODType 不是一个成员变量,只是一个成员类型,在后边的第一个测试函数会加以验证。
接下来要做的事情就是对内置类型进行特化。

template<>
struct TypeTraits<int>
{
    typedef TrueType IsPODType;
};

template<>
struct TypeTraits<char>
{
    typedef TrueType IsPODType;
};

template<>
struct TypeTraits<short>
{
    typedef TrueType IsPODType;
};

template<>
struct TypeTraits<size_t>
{
    typedef TrueType IsPODType;
};

template<>
struct TypeTraits<long>
{
    typedef TrueType IsPODType;
};

template<>
struct TypeTraits<double>
{
    typedef TrueType IsPODType;
};

template<class Ty>
struct TypeTraits<Ty*>
{
    typedef TrueType IsPODType;
};

在这里给出部内置类型的特化,相信读者已经看懂如何去特化参数为内置类型的类了,就不一一实现了。

接下来就是拷贝函数了

template<typename T>
void Copy(T* dest, const T* src, size_t size)
{
    //获取参数的类型的名称
    cout << "Typename is: " << typeid(T).name() << endl;
    if (TypeTraits<T>::IsPODType().Get())//是内置类型
    {
        memcpy(dest, src, size*sizeof(T));
    }
    else
    {
        for (size_t i = 0; i < size; i++)
        {
            dest[i] = src[i];
        }
    }
}

**注意:**typeid可以获取到一个类型的名称,但是不能拿来做变量的声明。

最后就是测试函数了

void FunTest1()//测试内置类型
{
    cout << sizeof(TypeTraits<int>) << endl;
    int arr[] = { 1, 2, 3, 4, 5, 6 };
    int array[10] = { 0 };
    size_t size = sizeof(arr) / sizeof(arr[0]);
    Copy(array, arr, size);
    for (size_t i = 0; i < size; i++)
    {
        cout << array[i] << " ";
    }
    cout << endl;
}

void FunTest2()//测试自定义类型
{
    string s1[10] = { "1235", "2abdc", "hdfiig", "asdfghjk" };
    string s2[10] = { "11", "22", "33" };
    Copy(s2, s1, 10);
}

int main()
{
    FunTest1();
    FunTest2();
    return 0;
}

先将第二个测试函数的调用注释掉,看第一个测试函数的结果:
C++类型萃取

对类TypeTraits求大小发现其大小为1,这说明这个类里边什么都没有,即IsPODType是并不是其成员变量。
Copy函数对内置类型进行拷贝,意料中的结果。调试看看Copy函数对自定义类型的拷贝是不是也是预料中的结果呢?
C++类型萃取

调试发现,对自定义类型的拷贝也很成功。

对类型萃取的讲解就到这里,欢迎读者提出宝贵意见哦~