函数模板

来源:互联网 发布:免费源码分享网站 编辑:程序博客网 时间:2024/06/05 22:52

函数模板

可以定义一个通用的函数模板(function template),而不是为每个类型都定义一个新的函数。

template <typename T>int compare(const T &v1, const T &v2){    if(v1<v2) return -1;    if(v2<v1) return 1;    return 0;}

模板定义以关键字template开始,后跟一个模板参数列表(template parameter list),这是一个以逗号分隔的一个或多个模板参数(template parameter)的列表,用<>包围起来。

Note:在模板定义中,模板参数列表不能为空

当使用模板的时候,我们(显式或者隐式地)指定模板实参(template argument),将其绑定在模板参数上。

实例化函数模板

编译器通常使用函数实参的类型来确定绑定到模板参数T的类型。例如:

cout << compare(1,0) << endl; //T为int

实参的类型是int,因此编辑器可以推断出模板实参为int,并将它绑定到模板参数T上。
编辑器用推断出的模板参数来为我们实例化(instantiate)一个特定版本的函数。例如,

//实例化出 int compare(const int&, const int&)cout << compare(1,0) << endl; //T为int//实例化出 int compare(const vector<int>&, const vector<int>&)vector<int> vec1(1,2,3), vec2(4,5,6);cout << compare(vec1, vec2) << endl; //T为vector<int>

这些被编译器生成的版本通常被称为模板的实例(instantiation)

模板类型参数

上文中的compare函数都有一个模板类型参数(type parameter)。我们可以将类型参数看作类型说明符,就像内置类型或者类类型说明符一样使用。类型参数可以用来:

  • 指定返回类型
  • 指定函数的参数类型
  • 在函数体内用于变量声明或类型转换
// ok: same type used for the return type and parametertemplate <typename T> T foo(T* p){    T temp = *p; //tmp will have the type to which p points    //...    return tmp;}

类型参数(type parameter)前面必须使用关键字class或者typename

// error: must precede U with either *typename* or *class*template <typename T, U> T calc(const T&, const U&);

在模板参数列表中,这两个关键字的含义相同,可以互换使用。一个模板参数列表中可以使用这两个关键字。

// ok: no distinction between *typename* and *class* in a template parameter listtemplate <typename T, class U> calc (const T&, const U&);

非类型模板参数

除了定义类型参数(type parameter),还可以在模板中定义非类型参数(nontype parameter)。一个非类型参数表示一个值而非类型参数。通过一个特定的类型名而不是关键字classtemplate来指定非类型参数。
当一个模板被实例化时,非类型参数被用户提供的或编译器推断出来的值所替代。
Note:这些值必须是常量表达式
例子:编写一个compare版本处理字符串字面常量(string literals),这种字面常量是const char的数组。由于不能拷贝一个数组,因此将参数定义为数组的引用[注意区分引用的数组以及数组的引用]。并且我们希望能够比较不同长度的字符串字面常量,因此模板定义了两个非类型参数(nontype parameter)。两个模板参数分别代表了两个数组的长度。

Reference:

template<unsigned N, unsigned M>int compare(const char (&p1)[N], const char (&p2)[M]){return strcmp(p1, p2);}

当调用这个版本的compare时:

compare("hi", "mom");

编译器会使用字面常量的大小来代替N和M,从而实例化模板。编译器会实例化出如下版本:

int compare(const char (&p1)[3], const char (&p2)[4]); //the compiler inserts a null terminator at the end of a string literal