C++ 模板
Templates
函数模板(Functions templates)
函数模板是可以运行通用类型的一种特殊函数。他可以适应于多种类型和类,不需要对于每个类都重复整个函数的代码。
函数模板可以在c++里面实现用temolate参数,template关键字可以使类型当作参数输入,就是常规函数可以让数值当作参数传递到函数当中。
声明函数模板的格式为:
template <class identifier> function_declaration;
template <typename identifier> function_declaration;
它们唯一的不同关键字class和typename,用起来都是一样的。
例如,使用模板函数来返回两个数中的最大数:
1 template <class myType> 2 myType GetMax (myType a, myType b) 3 { 4 return (a>b?a:b); 5 }
在使用函数模板时,我们可以通过该格式调用函数:
function_name <type> (parameters);
例如通过调用GetMax来比较两个数的大小,我们可以这样写:
int x,y; GetMax <int> (x,y);
因为上面的函数模板只接受了一个类型,函数在调用时接受了两个参数都是T类型,但是当接受了两个不同的参数,再没有<>特殊说明的情况下,编译器会报错,例如:
int i; long l; k = GetMax (i,l)
在这种情况下,我们可以声明多个类型来解决这个问题:
template <class T, class U> T GetMin (T a, U b) { return (a<b?a:b); }
类模板(class templates)
我们也可以写类模板,因此一个类里面的成员可以把类型当作参数输入,例如:
template <class T> class mypair { T values [2]; public: mypair (T first, T second) { values[0]=first; values[1]=second; } };
这样类在创造对象时,就可以存储任何类型的数据:
mypair<int> myobject (115, 36); mypair<double> myfloats (3.0, 2.18);
在编写类的函数实现过程中,需要在
1、每个函数前面加上 template <typename 虚拟类型>
2、T mypair<T>::getmax () 在类后面加上虚拟类型
3、 mypair <int> myobject (100, 75); 在声明对象时加入模板参数
// class templates #include <iostream> using namespace std; template <class T> class mypair { T a, b; public: mypair (T first, T second) {a=first; b=second;} T getmax (); }; template <class T> T mypair<T>::getmax () { T retval; retval = a>b? a : b; return retval; } int main () { mypair <int> myobject (100, 75); cout << myobject.getmax(); return 0; }
类模板的特殊化,如果我们想要对于一个特殊的类型不同的实现过程,我们可以定义一个特殊的模板,例如:
// template specialization #include <iostream> using namespace std; // class template: template <class T> class mycontainer { T element; public: mycontainer (T arg) {element=arg;} T increase () {return ++element;} }; // class template specialization: template <> class mycontainer <char> { char element; public: mycontainer (char arg) {element=arg;} char uppercase () { if ((element>='a')&&(element<='z')) element+='A'-'a'; return element; } }; int main () { mycontainer<int> myint (7); mycontainer<char> mychar ('j'); cout << myint.increase() << endl; cout << mychar.uppercase() << endl; return 0; }
注意通用类型模板和特殊模板的区别:
template <class T> class mycontainer { ... }; template <> class mycontainer <char> { ... };
template <class T=char, int N=10> class mysequence {..};
mysequence<> myseq;//当参数为空,则是默认参数
从编译器的角度来看,模板不是普通的函数或类。它们是按需编译的,这意味着模板函数的代码在需要特定模板参数的实例化之前不会被编译。此时,当需要实例化时,编译器将专门为模板中的参数生成一个函数。
由于模板是在需要时编译的,因此这会强制对多文件项目进行限制:模板类或函数的实现(定义)必须与其声明位于同一个文件中。这意味着我们不能在单独的头文件中分离接口,并且我们必须在使用模板的任何文件中包含接口和实现。
由于在需要时实例化模板之前不会生成代码,因此编译器准备允许在同一个项目中同时包含同一个模板文件,同时包含声明和定义,而不会生成链接错误。