c++模板与泛型编程(一)模板定义 ——《c++ primer》读书笔记

c++模板与泛型编程(一)模板定义 ——《c++ primer》读书笔记   by斜风细雨QQ:253786989    2012-02-26

  泛型编程就是指编写独立于特定类型的代码,c++ STL就是泛型编程的极致运用。比如vector,它就是一个泛型容器,它里面可以装n多种类的元素。在使用的时候,再去指定元素类型:vector vi;或者vector vf;

  模板是泛型编程的根基,没有模板的支持,泛型编程就无从谈起。

函数模板(function template

  函数模板是一种独立于类型的特殊函数,由函数模板可以产生针对特定类型的函数版本。

  如:

template 
int compare(const T &lhs, const T &rhs)
{
    if (lhs < rhs) return -1;
    if (rhs < lhs) return 1;
    return 0;
}

  compare既可以比较两个int类型的数,也可以比较两个string类型的字符串。从这就可以看出模板与泛型编程的强大。如果不运用模板技术,而且我既想比较int类型,又想比较string类型,又想比较自定义类型等等,那就要针对这些类型分别编写一个函数,这样既增加了代码量,也不容易维护。

  称为模板形参表,T就是一个模板形参,多个模板形参以逗号隔开,模板形参表不允许为空。

函数模板的使用

  如:

int main()
{
    cout << compare(3, 5) << endl;
    string s1 = "hello", s2 = "world";
    cout << compare(s1, s2) << endl;
}

  对于“compare(3, 5)”,编译器将首先推断出函数参数的类型为int,然后将int绑定到compare的模板形参T,这个过程成为实例化instantiate)了函数模板的一个实例。其实就是编译器帮助程序员编写了一个int版的compare

模板形参类型

  模板形参有两种类型,一种叫做类型形参(type parameter)。如上面的“typename T”就是类型形参,因为T代表一个类型。还有一种模板形参叫做非类型形参nontype parameter)。

  如:

template 
void array_init(T (&parm)[N])
{
    for (size_t i = 0; i != N; ++i)
    {
       parm[i] = i;
    }
}

  这里面“size_t N”就是非类型形参,因为它并不代表某个类型。当调用array_init时,编译器从数组实参计算出函数模板的非类型形参的值。如:

int ia[10];
array_init(ia);

  则编译器将函数模板array_init的形参绑定到int[10],从而实例化一个array_init版本如下:array_init(int (&)[10]),也就是N的值为10

模板形参的名字不能在模板内部重用

template 
int compare(const T &lhs, const T &rhs)
{
    typedef int T; //error
    // …
    return 0;
}

  这段代码会出现编译错误,因为模板形参T,在模板内部不能重用。

内联(inline)函数模板

  函数模板也可以声明为inline,格式如下(注意inline的位置):

template  inline int compare(const T &lhs, const T &rhs); 

类模板(class template

  所谓类模板就是说本类可以支持不同类型的对象。

  如:

template 
class Queue
{
public:
    Queue();
    T &front();
    const T &front()const;
    void push(const T &);
    void pop();    
    bool empty() const;
private:
    // ...
};

  类模板的定义与普通类的定义看起来差不多,主要不同就是类型T,使得Queue可以针对不同的类型实例化不同的类。如:

Queue qi;
Queue qs;

  需要注意的是类模板也仅仅是一个模板,它并不是一个类,所以:Queue q;是不会通过编译的,因为Queue并不是一个类型。而Queue才是根据类模板Queue实例化出来的一个具体的类,所以可以定义一个Queue类型的变量qi

在模板定义的内部指定类型

  这句话要结合具体的例子才能容易理解:

template 
Parm fcn(Parm* array, U value)
{
    Parm::size_type * p;
    // ...
}

  Parm是一个类,类既可以有数据成员和函数成员,也可以有类型成员,比如STL容器类都有一个类型成员:size_type。而在上面这个函数模板的内部,编译器在遇到“Parm::size_type”时,不知道它是一个数据,还是一个类型,通常编译器假定这样的名字是一个数据,所以“Parm::size_type * p”就是两个数据的相乘,这肯定不是我们想要的结果。为了让编译器知道“Parm::size_type”是一个类型,就要显示的在其前面加上“typename”,如下:

template 
Parm fcn(Parm* array, U value)
{
    typename Parm::size_type * p;
    // ...
}

编写泛型程序

  如下函数模板,如果用来比较某个类型的两个值,则程序员必须保证该类型支持“<”操作符,否则就会编译出错。比如某个自定义类型,如果没有定义“<”操作符,则无法使用该函数模板。

template 
int compare(const T &lhs, const T &rhs)
{
    if (lhs < rhs) return -1;
    if (rhs < lhs) return 1;
    return 0;
}

  编写泛型程序时,模板参数通常使用const引用,这样该模板就可以使用不允许赋值的类型。另外编写模板内部的操作时尽量减少对类型T的要求。比如上面的函数如果像下面这样写,就要要求类型T同时支持“<”操作符和“>”操作符了。

template 
int compare(const T &lhs, const T &rhs)
{
    if (lhs < rhs) return -1;
    if (lhs > rhs) return 1;
    return 0;
}

c++模板与泛型编程(一)模板定义 ——《c++ primer》读书笔记   by斜风细雨QQ:253786989    2012-02-26

 

 

你可能感兴趣的:(C/C++,c++,编程,读书,编译器,string,vector)