C++类型萃取
程序员文章站
2022-06-10 13:50:29
...
一.问题的引入
首先我们如果要写一个拷贝函数,代码如下:
template<class T>
void Copy(T *dst, T *src, size_t size)
{
memcpy(dst, src, sizeof(T)*szie);
}
但是这个代码拷贝内置类型的没有问题,但是如果是自定义类型的,就牵扯到深浅拷贝问题,就行不通了,所以我们需要做的就是在代码内部判断传过来的数据类型,从而进行不同的操作。代码如下
template<class T>
void Copy(T *dst, T *src, size_t size)
{
if (内置类型)
{
memcpy(dst, src, sizeof(T)*size);
}
else//自定义类型
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
}
}
但是怎么进行类型判断呢?代码如下:
bool IsPOD(const char *TypeName)
{
static char *p[] = { "int", "double", "float" };
int len = sizeof(p) / sizeof(*p);
for (int i = 0; i < len; ++i)
{
if (strcmp(p[i], TypeName) == 0)//为自定义类型返回true
return true;
}
return false;
}
这样的话我们只需要在Copy的函数if语句中调用这个IsPOD函数就可以区分自定义类型和内置类型了,从而解决了之前类型不同的问题。
完整的代码如下:
bool IsPOD(const char *TypeName)
{
static char *p[] = { "int", "double", "float" };
int len = sizeof(p) / sizeof(*p);
for (int i = 0; i < len; ++i)
{
if (strcmp(p[i], TypeName) == 0)//为自定义类型返回true
return true;
}
return false;
}
template<class T>
void Copy(T *dst, T *src, size_t size)
{
if (IsPOD(typeid(T).name()))
{
memcpy(dst, src, sizeof(T)*size);
}
else
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
}
}
int main()
{
int a1[] = { 1, 2, 3, 4, 5 };
int a2[5];
string s1[] = { "1111", "2222", "3333", "4444" };
string s2[4];
Copy(a2, a1, sizeof(a1) / sizeof(*a1));
Copy(s2, s1, sizeof(s1) / sizeof(s1[0]));
system("pause");
return 0;
}
二.类型萃取
类型萃取的功能和上述代码一样,就是用来提取代码类型的,不过具体的实现步骤是什么样的呢,我们继续往下看
首先给出如下代码
struct TrueType
{
static bool IsPODType()
{
return true;
}
};
struct FalseType//对应自定义类型的处理
{
static bool IsPODType()
{
return false;
}
};
//什么类型都可以处理
template<class T>//所有的类型都扔进去处理
struct TypeTraits
{
typedef FalseType PODtype;//将数据类型看成自定义的类型来处理不会出错
};
相信这段代码有一定基础的同学一定可以看懂,接下来看Copy中如何使用上面的模版
template<class T>
void Copy(T *dst, T *src, size_t size)
{
if (TypeTraits<T>::PODtype::IsPODType())
{
memcpy(dst, src, sizeof(T)*size);
}
else
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
}
}
但是这样无法识别自定义类型和内置类型,因为无论扔过去什么都会返回false,怎么解决这个问题呢,这就要用到模版的特化
代码如下:
//什么类型都可以处理
template<class T>//所有的类型都扔进去处理
struct TypeTraits
{
typedef FalseType PODtype;//将数据类型看成自定义的类型来处理不会出错
};
template<>
struct TypeTraits<int>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<char>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<double>
{
typedef TrueType PODtype;
};
这样的话就可以处理不同的类型的
下面给出完整的代码包括测试代码:
struct TrueType
{
static bool IsPODType()
{
return true;
}
};
struct FalseType//对应自定义类型的处理
{
static bool IsPODType()
{
return false;
}
};
//什么类型都可以处理
template<class T>//所有的类型都扔进去处理
struct TypeTraits
{
typedef FalseType PODtype;//将数据类型看成自定义的类型来处理不会出错
};
template<>
struct TypeTraits<int>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<char>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<double>
{
typedef TrueType PODtype;
};
template<class T>
void Copy(T *dst, T *src, size_t size)
{
if (TypeTraits<T>::PODtype::IsPODType())
{
memcpy(dst, src, sizeof(T)*size);
}
else
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
}
}
int main()
{
int a1[] = { 1, 2, 3, 4, 5 };
int a2[5];
string s1[] = { "1111", "2222", "3333", "4444" };
string s2[4];
Copy(a2, a1, sizeof(a1) / sizeof(*a1));
Copy(s2, s1, sizeof(s1) / sizeof(s1[0]));
system("pause");
return 0;
}
下面给出内定类型的执行过程,因为自定义类型和内置类型的执行过程和原理一样,下面可以自己去测试
以上就是类型萃取,其实就是模版的特化的应用!
其实上面的完整类型萃取也可以写成如下的方式,代码如下:
struct TrueType
{};
struct FalseType//对应自定义类型的处理
{};
//什么类型都可以处理
template<class T>//所有的类型都扔进去处理
struct TypeTraits
{
typedef FalseType PODtype;//将数据类型看成自定义的类型来处理不会出错
};
template<>
struct TypeTraits<int>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<char>
{
typedef TrueType PODtype;
};
template<>
struct TypeTraits<double>
{
typedef TrueType PODtype;
};
template<class T>
void Copy(T *dst, T *src, size_t size, TrueType)
{
memcpy(dst, src, sizeof(T)*size);
}
template<class T>
void Copy(T *dst, T *src, size_t size, FalseType)
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
}
template<class T>
void Copy(T *dst, T *src, size_t size)
{
Copy(dst, src, size, TypeTraits<T>::PODtype());
}
int main()
{
int a1[] = { 1, 2, 3, 4, 5 };
int a2[5];
string s1[] = { "1111", "2222", "3333", "4444" };
string s2[4];
Copy(a2, a1, sizeof(a1) / sizeof(*a1));
Copy(s2, s1, sizeof(s1) / sizeof(s1[0]));
system("pause");
return 0;
}
下一篇: Android计算器界面布局