C++ 模板
-
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
-
模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
-
每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如
vector <int>
或vector <string>
。 -
您可以使用模板来定义函数和类,接下来让我们一起来看看如何使用。
一.函数模板
1.模板函数定义
template <typename 模板类型1, typename 模板类型2, ...>
返回值类型 函数名字(参数列表...)
{
//函数主体
//...
}
//即如下:
template <typename type> ret-type func-name(parameter list)
{
// 函数的主体
}
如交换数据的函数模板如下:
template <typename T>
void swap(T &a, T& b)
{
T temp = a;
a = b;
b = temp;
}
/* 使用 */
int a = 1;
int b = 2;
swap<int>(a, b)
2.不用模板&用模板
2.1.不使用模板实现值交换
/* 交换两个整型值 */
void swap(int &a, int& b)
{
...
}
/* 交换两个浮点值 */
void swap(float &a, float& b)
{
...
}
/* 交换两个字符串 */
void swap(string &a, string& b)
{
...
}
/* 交换两个列表 */
void swap(list &a, list& b)
{
...
}
2.2.使用模板简化操作
template <typename T>
void swap(T &a, T& b)
{
T temp = a;
a = b;
b = temp;
}
int main(int argc, char *argv[])
{
int a = 1;
int b = 2;
float c = 0.1;
float d = 0.2;
swap<int>(a, b);
swap<float>(c, d);
}
编译器就会自动生成以下代码:
void swap(int &a, int& b)
{
...
}
void swap(float &a, float& b)
{
...
}
int main(int argc, char *argv[])
{
int a = 1;
int b = 2;
float c = 0.1;
float d = 0.2;
swap(a, b);
swap(c, d);
}
这样我们平时一些重复的代码就可以利用模板特性让编译器自动生成了,从而提高程序可靠性和简化代码的实现
3.函数模板威力
使用模板函数来实现编译期计算数组长度(在编译期就能获取到数组长度)。
template <typename T, size_t N>
inline size_t GetArrayLength(const T(&)[N])
{
return N;
}
/* 使用 */
int array[] = {0, 1, 2, 3, 4, 5};
cout << GetArrayLength<int>(array) << endl;
cout << GetArrayLength(array) << endl; /* 可省略类型,让编译器自动推导。 */
/* 输出: 6 */
tip: 增加了 inline 关键字的函数称为“内联函数”。内联函数和普通函数的区别在于:当编译器处理调用内联函数的语句时,不会将该语句编译成函数调用的指令,而是直接将整个函数体的代码插人调用语句处,就像整个函数体在调用处被重写了一遍一样。
size_t是一些C/C++标准在
stddef.h
中定义的。这个类型足以用来表示对象的大小。size_t的真实类型与操作系统有关,与int固定四个字节不同有所不同,size_t的取值range是目标平台下最大可能的数组尺寸,一些平台下size_t的范围小于int的正数范围,又或者大于unsigned int. 使用Int既有可能浪费,又有可能范围不够大。
二.类模板
1.类模板定义
template <class 模板类型1, class 模板类型2, ...>
class 类名
{
//...
}
2.类模板的使用
template<class T>
class List
{
public:
const T &at(int i) const
{
return m_list.at(i);
}
void append(const T &t)
{
m_list.push_back(t);
}
private:
vector<T> m_list;
};
/* 使用 */
List<string> stringList;
stringList.append("Hello world");
cout << stringList.at(0);
3.类模板,实现不同类的单例
template<typename T>
class Singleton
{
public:
inline static T& getInstance()
{
static T _instance;
return _instance;
}
private:
Singleton();
Singleton(Singleton const&);
~Singleton();
Singleton& operator= (Singleton const&);
};
/* 使用 */
string str = Singleton<string>::getInstance();
4.利用模板针对性能优化
template<typename T, int N>
class Copy
{
public:
static inline void exec(T *in, T *out)
{
Copy<T, N - 1>::exec(in, out);
out[N - 1] = in[N - 1];
}
};
template<typename T>
class Copy<T, 0> /* 特化, 用于结束递归 */
{
public:
static inline void exec(T *in, T *out) { }
};
template<typename T, int N>
void copy(T (&in)[N], T (&out)[N])
{
Copy<T, N>::exec(in, out);
}
/* 使用 */
int in[5] = {1, 2, 3, 4, 5};
int out[5] = {0};
copy(in, out);
尽管上面例子在一维数组基本没什么优化,但在用在多维数组上却是可以优化数据的分页缓存刷新,从而提升性能。