萃取第一次接触是在高中的化学课中,看来学好c++还得懂化学啊,哈哈!(PS:开玩笑的!)首先我解释下化学中的萃取。
利用溶质在两种互不相容的溶剂里溶解度的不同,用一种溶剂将溶质从另一种溶剂中提取出来。比如汽油洗衣服上的油渍。
感谢我的高中化学李老师。
开始c++中的萃取:
先看看什么是特化

模板特化分为两种:全特化、偏特化
全特化

偏特化
偏特化也叫做局部特化,也就是局部的参数特化。

这就是萃取的支持,编译器会优先选择特化版本(全特化、偏特化)
萃取
很久很久以前,C 语言统一了江湖。几乎所有的系统底层都是用 C 写的,当时定义的基本数据类型有 int、char、float 等整数类型、浮点类型、枚举、void、指针、数组、结构等等。然后只要碰到一串 01010110010 之类的数据,编译器都可以正确的把它解析出来。
那么到了 C++ 诞生之后,出现了继承、派生这样新的概念,于是就诞生了一些新的数据结构。比如某个派生类,C 语言中哪有派生的概念啊,遇到这种数据编译器就不认识了。可是我们的计算机世界里,主要的系统还是用 C 写的啊,为了和旧的 C 数据相兼容,C++ 就提出了 POD 数据结构概念。
POD 是 Plain Old Data 的缩写,是 C++ 定义的一类数据结构概念,比如 int、float 等都是 POD 类型的。Plain 代表它是一个普通类型,Old 代表它是旧的,与几十年前的 C 语言兼容,那么就意味着可以使用 memcpy() 这种最原始的函数进行操作。两个系统进行交换数据,如果没有办法对数据进行语义检查和解释,那就只能以非常底层的数据形式进行交互,而拥有 POD 特征的类或者结构体通过二进制拷贝后依然能保持数据结构不变。也就是说,能用 C 的 memcpy() 等函数进行操作的类、结构体就是 POD 类型的数据。
类型萃取,在STL中用到的比较多,用于判断一个变量是否为POD类型.
简述来说可以用来判断出某个变量是内置类型还是自定义类型.
通过类型萃取,萃取到变量类型,对不同变量进行不同处理,可以提升程序效率.
接下来看看代码:
struct _TrueType
{
bool Get()
{
return true;
}
};
struct _FalseType
{
bool Get()
{
return false;
}
};
template<typename T>
struct _TypeTraits
{
typedef _FalseType _IsPODType;
};
template<>
struct _TypeTraits < int >
{
typedef _TrueType _IsPODType;
};
template<typename T>
void Copy(T *dest, const T *src, size_t sz)
{
if (_TypeTraits<T>::_IsPODType().Get())
{
cout << "内置类型用memcpy函数进行拷贝:" << endl;
memcpy(dest, src, sz * sizeof(T));
}
else
{
cout << "自定义类型用for循环进行拷贝:" << endl;
for (size_t i = 0; i < sz; i++)
{
*(dest + i) = *(src + i);
}
}
}
int main()
{
cout << "内置类型的拷贝:\n";
int array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t size = sizeof(array1) / sizeof(array1[0]);
int array2[size] = { 1, 2, 3 };
Copy(array2, array1, size);
for (size_t i = 0; i < size; i++)
{
cout << array2[i] << " ";
}
cout << endl;
cout << "\n************华丽的分割线************\n\n";
cout << "自定义类型string类对象的拷贝:\n";
string s1[] = { "11111", "22222", "33333", "44444", "55555" };
const size_t size1 = sizeof(s1) / sizeof(s1[0]);
string s2[size1] = { "abcd" };
Copy(s2, s1, size1);
for (size_t i = 0; i < size1; i++)
{
cout << s2[i].c_str() << endl;
}
system("pause");
return 0;
}
结果:

原理大概就这个样子。
看看下面这个,就是应用。

2023-10-03补充,在C++17中可如下操作:
template<typename T>
struct IsPOD :false_type
{
};
template<>
struct IsPOD<int> :true_type
{
};
template<>
struct IsPOD<char> :true_type
{
};
template<typename T>
void Copy(T* dest, T* src, size_t size)
{
if (IsPOD<T>::value == true)
{
cout << "内置类型用memcpy函数进行拷贝:" << endl;
memcpy(dest, src, size * sizeof(T));
}
else
{
cout << "自定义类型用for循环进行拷贝:" << endl;
for (size_t i = 0; i < size; i++)
{
*(dest + i) = *(src + i);
}
}
}
int main()
{
cout << "内置类型的拷贝:\n";
int array1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t size = sizeof(array1) / sizeof(array1[0]);
int array2[size] = { 1, 2, 3 };
Copy(array2, array1, size);
for (size_t i = 0; i < size; i++)
{
cout << array2[i] << " ";
}
cout << endl;
cout << "\n************华丽的分割线************\n\n";
cout << "自定义类型string类对象的拷贝:\n";
string s1[] = { "11111", "22222", "33333", "44444", "55555" };
const size_t size1 = sizeof(s1) / sizeof(s1[0]);
string s2[size1] = { "abcd" };
Copy(s2, s1, size1);
for (size_t i = 0; i < size1; i++)
{
cout << s2[i].c_str() << endl;
}
system("pause");
return 0;
}
结果:


229





