定义模板——函数模板和类模板

面向对象编程(OOP)和泛型编程都能处理在编写程序时不知道类型的情况。不同之处在于:OOP能处理类型在程序运行之前都未知的情况;而在泛型编程中,在编译时就能获知类型了

前面介绍的容器、迭代器和算法都是泛型编程的例子。当我们编写一个泛型程序时,是独立与任何特定类型来编写代码的。当使用一个泛型程序时,我们提供类型或值,程序实例可在其上运行。

模板是泛型编程的基础。一个模板就是一个创建类或函数的蓝图或者说公式。当使用一个vector这样的泛型类型,或者find这样的泛型函数时,我们提供足够的信息,将蓝图转换为特定的类型函数。这种转换发生在编译时。

定义模板

假定我们希望编写一个函数来比较两个值,并指出第一个值是小于、等于还是大于第二个值。在实际中,我们可能想要定义多个函数,每个函数比较一个给定类型的值。我们的初次尝试可能定义多个重载函数:

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

int compare(const double &v1,const string &v2)
{
    if(v1<v2) return -1;
    if(v1>v2) return 1;
    return 0;
}

这两个函数几乎相同,唯一的差别是参数的类型,函数体则完全一样。

如果对每种希望比较的类型都不得不重复定义完全一样的函数体,是非常烦琐且容易出错的。更麻烦的是,在编写程序的时候,我们就要确定可能要compare的所有类型。

函数模板

我们可以定义一个通用的函数模板,而不是为每个类型都定义一个新函数。一个函数模板就是一个公式,可用来生成针对特定类型的函数版本。compare的模板版本可能像下面这样:

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

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

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

模板参数列表的作用很像函数参数列表。函数参数列表定义了若干特定类型的局部变量,但并未指出如何初始化它们。在运行时,调用者提供实参来初始化形参。

类似的,模板参数表示在类或函数定义中用到的类型或值。当使用模板时,我们(隐式地或显式地)指定模板实参(template argument),将其绑定到模板参数上。

我们的compare函数声明了一个名为T的类型参数。在compare中,我们用名字T表示一个类型。而T 表示的实际类型则在编译时根据compare的使用情况来确定。

实例化函数模板

当我们调用一个函数模板时,编译器(通常)用函数实参来为我们推断模板实参。即,当我们调用compare时,编译器使用实参的类型来确定绑定到模板参数T的类型。例如,在下面的调用中:

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

实参类型是int。编译器会推断出模板实参为int,并将它绑定到模板参数T。

编译器用推断出的模板参数来为我们实例化一个特定版本的函数。当编译器实例化一个模板时,它使用实际的模板实参代替对应的模板参数来创建出模板的一个新“实例”。

例如,给定下面的调用:

//实例化出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>

编译器会实例化出两个不同版本的compare。对于第一个调用,编译器会编写并编译一个compare版本,其中T被替换为int:

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

对于第二个调用,编译器会生成另一个compare版本,其中T被替换为vector<int>,这些编译器生成的版本通常被称为模板的实例。

模板类型参数

我们的compare函数有一个模板类型参数,一般来说,我们可以将类型参数看作类型说明符,就像内置类型或类类型说明符一样使用。特别是,类型参数可以用来指定返回类型或函数的参数类型,以及在函数体内用于变量声明或类型转换。

类型参数必须使用关键字class或typename:

//错误:U之前必须加上class或typename

template <typename T,U> T calc(const T&,const U&);

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

//正确:在模板参数列表中,typename和class没有什么不同

template<typename T,class U> calc(const T&,const U&);

看起来用关键字typename来指定模板类型参数比用class更为直观。毕竟,我们可以用内置(非类)类型作为模板类型实参。而且,typename更清楚地指出随后的名字是一个类型名。

 

非类型模板参数

除了定义类型参数,还可以在模板定义中定义非类型参数。一个非类型参数表示一个值而非一个类型。我们通过一个特定的类型名而非关键字class 或 typename来指定非类型参数。

当一个模板被实例化时,非类型参数被一个用户提供的或编译器推断出的值所代替。这些值必须是常量表达式,从而允许编译器在编译时实例化模板。

 

时间: 2024-09-20 01:07:31

定义模板——函数模板和类模板的相关文章

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

C++函数模板与类模板实例解析_C 语言

本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程(Generic Programming)是一种编程范式,通过将类型参数化来实现在同一份代码上操作多种数据类型,泛型是一般化并可重复使用的意思.泛型编程最初诞生于C++中,目的是为了实现C++的STL(标准模板库). 模板(template)是泛型编程的基础,一个模板就是一个创建类或函数的蓝图或公式.例如,当使用一个vector这样的泛型类型或者find这样的泛型函数

ios-自定义类系统自带的类模板没有了、怎么办啊!

问题描述 自定义类系统自带的类模板没有了.怎么办啊! 每次新建继承系统的类的文件都是光秃秃的!太不方便了,原来新建都会自带类模板的啊?求解 解决方案 类模板多种类型的类模板自定义类模板,类模板的默认类型数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器 解决方案二: 楼主指的是什么环境什么编辑器 解决方案三: 我觉得你是不是直接选了Objective-C文件,而不是cocoa touch class

c++类模板中静态成员变量的声明定义

我们知道,c++中,类的静态成员是要在.cpp文件中定义的,如果在.h中定义,会出现重复定义. 但是在写类模板时,一般所有的代码都是放在.h文件中的,如果要做分离是一件很麻烦的事.那如果出现了静态成员怎么办? 如: // ==== ca.h ===== template<class T> class ca { public:     static std::vector<T> m_vec;     }; 对于这个m_vec怎么办呢?难道要我们在每个使用该类模板的.cpp中,都手动增

C++中的类模板详解及示例_C 语言

C++中的函数模板 对于类的声明来说,也有同样的问题.有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,如下面语句声明了一个类: 复制代码 代码如下: class Compare_int{ public:  Compare(int a,int b)  {   x=a;   y=b;  }   int max()  {   return (x>y)?x:y;  }  int min()  {   return (x<y)?x:y;  } private:  int x,y;}; 其作用是

C++类模板与模板类深入详解_C 语言

1.在c++的Template中很多地方都用到了typename与class这两个关键字,而且有时候二者可以替换,那么是不是这两个关键字完全一样呢? 事实上class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型,这样在定义模板的时候就可以使用下面的方式了:      t

类模板

---恢复内容开始--- 感觉C++ templates这本书写的不怎么好,挑写重点记一下: 1 与函数模板一样,只能在同一个头文件中声明和定义类. 类模板的声明 类模板的声明和函数模板的声明很相似:在声明之前,我们先(用一条语句)声明作为类型参数的标志符:我们继续使用T作为标志符: template <typename T> class Stack{ ... }; 在此,我们可以使用关键字class代替typename. 在类模板的内部,T可以像其他任何类型一样,用于声明成员变量和成员函数.

C++类模板的三种特化

说起C++的模板及模板特化,相信很多人都很熟悉,但是说到模板特化的几种类型,相信了解的人就不是很多.我这里归纳了模板特化的几种类型,一是特化为绝对类型:而是特化为引用,指针类型:三是特化为另外一个模板类. 这里用一个简单的例子来说明这三种情况: // general version template<class T> class Compare { public: static bool IsEqual(const T& lh, const T& rh) { return lh

C++类模板

在上篇文章(C++函数模板)中,主要介绍了C++中函数模板,与函数相似,类也可以被一种或多种类型参数化.容器类就是一个具有这种特性的典型的例子, 本文地址:http://www.cnblogs.com/archimedes/p/cpp-class-template.html,转载请注明源地址. 以下通过设计一个类模板Stack的实现来说明: 类模板Stack的实现 #include<iostream> #include<vector> #include<stdexcept&g

类模板的类名称后面可以跟类型参数!

问题描述 类模板的类名称后面可以跟类型参数! template class class_name{ }; template class class_name{ };这段代码为什么能够编译过去,请问这样写的目的是什么? 解决方案 C++ 类模板与无类型参数类模板参数