定义模板时, 使用关键字typename
还是class
没有区别,两个都可以用。
1 函数模板
下例是函数模板的定义及使用,可以看出,函数模板的调用方式同一般函数:
// returns 0 if the values are equal, 1 if v1 is larger, -1 if v1 is smaller
template <typename T> // 模板参数列表, 由逗号分隔,一个或多个,不能为空
int compare(const T &v1, const T &v2)
{
if (v1 > v2) return 1;
if (v1 < v2) return -1;
return 0;
}
int main () {
// 编译器实例化为int compare(const int&, const int&)
cout << compare(1, 0) << endl;
// 编译器实例化为int compare(const string&, const string&)
string s1 = "hi", s2 = "world";
cout << compare(s1, s2) << endl;
return 0;
}
对于内联函数模板,inline
关键字必须位于模板参数列表和函数返回类型的中间。
// OK: inline specifier follows template parameter list
template <typename T> inline T min(const T&, const T&);
// !!! ERROR: inline 不能放在template关键字之前
inline template <typename T> T min(const T&, const T&);
2 类模板
类模板的定义形式及使用如下所示:
template <class Type> class Queue {
public:
Queue (); // default constructor
Type &front (); // return element from head of Queue
const Type &front () const;
void push (const Type &); // add element to back of Queue
void pop(); // remove element from head of Queue
bool empty() const; // true if no elements in the Queue
private:
// ...
};
int main() {
Queue<int> qi; // Queue that holds ints
Queue< vector<double> > qc; // Queue that holds vectors of doubles
Queue<string> qs; // Queue that holds strings
return 0;
}
3 模板编译模型
不同于一般函数和类定义,对于模板,编译器要求看到调用模板函数或模板类的成员函数时,也要求能看到定义。C++定义了两种编译模板代码的模型:包含编译模型(Inclusion Compilation Model) 和单独编译模型(Separate Compilation Model), 以支持声明和实现,或定义和实现分别放在头文件和源文件中的项目组织形式。
否则,要通过编译,模板的实现必须放在头文件中。
3.1 包含编译模型 (Inclusion Compilation Model)
这种编译模型,所有的编译器都支持。
// 头文件 utlities.h
#ifndef UTLITIES_H // header gaurd (Section 2.9.2, p. 69)
#define UTLITIES_H
template <class T> int compare(const T&, const T&);
// other declarations
#include "utilities.cc" // get the definitions for compare etc.
#endif
----------------------------------------------------------------
// 源文件 utlities.cc
template <class T> int compare(const T &v1, const T &v2)
{
if (v1 > v2) return 1;
if (v1 < v2) return -1;
return 0;
}
// other definitions
用VS2010测试:
//file: my_template.h
#ifndef MY_TEMPLATE_H
#define MY_TEMPLATE_H
template<typename T> int compare(const T&, const T&);
#include "my_template.cpp" # Most import line for build
#endif
-----------------------------------------------------
//file: my_template.cpp
#include "stdafx.h"
// 注意,这里不能加 #include "my_template.h", 加了就无法编译通过。
template<typename T> int compare(const T& v1, const T& v2) {
if (v1 > v2) return 1;
if (v1 < v2) return -1;
return 0;
}
-----------------------------------------------------
// file with main:
#include "stdafx.h"
#include "my_template.h"
#include <iostream>
using std::cout;
using std::endl;
int _tmain(int argc, _TCHAR* argv[])
{
cout << compare(3, 1) << endl;
system("pause");
return 0;
}
// 可以成功执行,输出 1.
对于函数模板,这种方法ok。
但是测试中发现,对于模板类,如果加了类似 include “source.cpp”
的指令,会出现“函数模板已经定义”的错误,所以,把模板类的实现也放在头文件中,将是省时省力的做法。
3.2 单独编译模型 (Separate Compilation Model)
这种编译模型使用了关键字export
。
对于函数,只需在源文件中的函数定义前加export
关键字。
// the template definition goes in a separately-compiled source file
export template <typename Type> Type sum(Type t1, Type t2) /* ...*/
对于类,略有不同:
// 头文件
template <class Type> class Queue { ... };
-------------------------------------------------------------
// 源文件
export template <class Type> class Queue;
#include "Queue.h"
// Queue member definitions
由于VS2010 说它不支持export
关键字,这种编译模型没测试过。
[1] C++ Primer Chapter 16 Templates and Generic Programming