再谈模板
1、非类型模板参数
模板参数分为类类型参数和非类型参数
类类型参数:出现在模板参数列表中,跟在class或者typename的参数类型名称
非类型参数:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可以将该参数当成常量使用
注:
1、浮点数,类对象以及字符串不允许作为非类型模板参数
2、非类型模板参数必须在编译器就能确认结果
#include <iostream>
using namespace std;
namespace gwp
{
//定义一个模板类型的静态数组
template<class T, size_t N= 10>
class array
{
public:
T& operator(size_t index)
{
return m_array[index];
}
const T& operator(size_t index) const
{
return m_array[index];
}
size_t size() const
{
return m_size;
}
bool empty() const
{
return (m_size == 0) ? true : false;
}
private:
T m_array[N];
size_t m_size;
};
}
int main()
{
system("pause");
return 0;
}
2、模板特化
模板的特化:
模板在遇到一些特殊类型的时候会出错,就需要对模板进行特化
模板的特化分为类模板特化和函数模板特化
#include <iostream>
using namespace std;
template<class T>
bool isEqual(T& left, T& right)
{
return (left == right) ? 1 : 0;
}
int main()
{
char* p1 = "Hello";
char* p2 = "World";
cout << isEqual(p1, p2) << endl;
system("pause");
return 0;
}
2.1、函数模板的特化
函数模板特化的步骤
1、必须先有一个函数模板
2、template<> 函数返回值 需要特化的函数名<需要特化的类型>(参数列表)
3、函数的形参列表必须和需要特化的类型一致
#include <iostream>
using namespace std;
template<class T>
bool isEqual(T& left, T& right)
{
return (left == right) ? true : false;
}
template<>
bool isEqual<char*>(char*& left, char*& right)
{
return (strcmp(left, right) == 0) ? true : false;
}
int main()
{
char* p1 = "Hello";
char* p2 = "World";
char* p3 = "World";
cout << isEqual(p1, p2) << endl;
cout << isEqual(p2, p3) << endl;
system("pause");
return 0;
}
2.2、类模板的全特化
全特化是将模板参数列表中所有的参数都特化
#include <iostream>
using namespace std;
template<class T1, class T2>
class Data
{
public:
Data()
{
cout << "Data()<T1, T2>" << endl;
}
private:
T1 m_d1;
T2 m_d2;
};
template<>
class Data<int, char>
{
public:
Data()
{
cout << "Data()<int, char>" << endl;
}
private:
int m_d1;
char m_d2;
};
int main()
{
Data<int, int> data1;
Data<int, char> data2;
system("pause");
return 0;
}
2.3、类模板的偏特化
类模板的偏特化是指任何模板参数进一步进行条件限制的特化版本
类模板的偏特化分为两种
一种是部分特化:将模板参数的一部分特化
另外一种是参数的进一步限制:偏特化也可以是将模板参数进行更进一步的限制,而设计出的模板
#include <iostream>
using namespace std;
template<class t1, class t2>
class data
{
public:
data()
{
cout << "data()<t1, t2>" << endl;
}
private:
t1 m_d1;
t2 m_d2;
};
template<class t2>
class data<int, t2>
{
public:
data()
{
cout << "data()<int, t2>" << endl;
}
private:
int m_d1;
t2 m_d2;
};
template<class t1>
class data<t1, char>
{
public:
data()
{
cout << "data()<t1, char>" << endl;
}
private:
t1 m_d1;
char m_d2;
};
template<class t1, class t2>
class data<t1*, t2*>
{
public:
data()
{
cout << "data()<t1*, t2*>" << endl;
}
private:
t1* m_d1;
t2* m_d2;
};
template<class t1, class t2>
class data<t1&, t2&>
{
public:
data(const t1& d1, const t2& d2)
:m_d1(d1)
, m_d2(d2)
{
cout << "data(t1&, t2&)" << endl;
}
private:
const t1& m_d1;
const t2& m_d2;
};
int main()
{
data<double, int> d1; // 调用特化的int版本
data<int, double> d2; // 调用基础的模板
data<int *, int*> d3; // 调用特化的指针版本
data<int&, int&> d4(1, 2); // 调用特化的指针版本
system("pause");
return 0;
}
3、模板特化的应用,类型萃取
如何写一个通用的拷贝函数
#include <iostream>
#include <cstring>
#include <string>
#include <typeinfo>
using namespace std;
//类模板特化的应用:类型萃取
//使用memcpy进行拷贝(浅拷贝,对自定义类型无效)
template <class T>
void _copy1(T* dst, T* src, size_t size)
{
memcpy(dst, src, sizeof(T*)*size);
}
//使用赋值方式拷贝(效率较低)
template<class T>
void _copy2(T* dst, T* src, size_t size)
{
for (size_t i = 0; i < size; i++)
{
dst[i] = src[i];
}
}
//增加bool类型区分自定义类型和内置类型
template<class T>
void _copy3(T* dst, T* src, size_t size, bool IsPODType)
{
if (IsPODType)
{
memcpy(dst, src, sizeof(T*)*size);
}
else
{
for (size_t i = 0; i < size; i++)
{
dst[i] = src[i];
}
}
}
//使用函数区分内置类型和自定义类型
bool IsPODType(const char* strType)
{
const char* arrType[] = { "char", "short", "int", "long", "long long", "float", "double", "long double" };
for (size_t i = 0; i < sizeof(arrType) / sizeof(arrType[0]); i++)
{
if (!strcmp(strType, arrType[i]))
{
return true;
}
}
return false;
}
template<class T>
void _copy4(T* dst, T* src, size_t size)
{
if (IsPODType(typeid(T).name()))
{
memcpy(dst, src, sizeof(T*)*size);
}
else
{
for (size_t i = 0; i < size; i++)
{
dst[i] = src[i];
}
}
}
int main()
{
string s1[3] = { "11", "22", "33" };
string s2[3];
_copy1(s2, s1, 3);
_copy2(s2, s1, 3);
_copy3(s2, s1, 3, true);
_copy3(s2, s1, 3, false);
_copy4(s2, s1, 3);
system("pause");
return 0;
}
#include <iostream>
using namespace std;
//代表内置类型
class TrueType
{
public:
static bool Get()
{
return true;
}
};
//代表自定义类型
class FalseType
{
public:
static bool Get()
{
return false;
}
};
template<class T>
class TypeTraits
{
public:
typedef FalseType IsPODType;
};
template<>
class TypeTraits<char>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<short>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<int>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<long>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<long long>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<float>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<double>
{
public:
typedef TrueType IsPODType;
};
template<>
class TypeTraits<long double>
{
public:
typedef TrueType IsPODType;
};
template<class T>
void _copy(T* dst, T* src, size_t size)
{
if (TypeTraits<T>::IsPODType::Get())
{
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, 6, 7, 8, 9 };
int a2[10];
_copy(a2, a1, 10);
string s1[] = { "111", "222", "333", "444" };
string s2[4];
_copy(s2, s1, 4);
system("pause");
return 0;
}
4、模板的分离编译
分离编译:一个程序或者项目由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有的文件链接起来,形成单一的可执行文件的过程
模板的分离编译指的是将模板的声明和定义分离开,头文件中声明,源文件中定义
a.h
#include <iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right);
a.cpp
#include "a.h"
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
cout << Add(1, 2) << endl;
cout << Add(2.2, 3.3) << endl;
system("pause");
return 0;
}
5、模板的优缺点
优点:
1、模板复用了代码,节省资源,更快的迭代开发
2、增强了代码的复用性
缺点:
1、模板会导致代码膨胀
2、出现模板编译错误,不易定位错误信息