C++学习笔记12-模板1

 1.  函数模板

函数模板是一个独立于类型的函数,可作为一种方式。产生函数的特定类型版本号。

// implement strcmp-like generic compare function

 // returns 0 if thevalues 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 (v2 < v1)return 1;

 return 0;

 }

2. 类模板

类模板也是模板。因此必须以keywordtemplate 开头,后接模板形參表。Queue 模板接受一个名为Type 的模板类型形參。

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:

 // ...

 };

3. 模板形參

像函数形參一样,程序猿为模板形參选择的名字没有本质含义。在我们的样例中,将compare 的模板类型形參命名为T,但也能够将它命名为随意名字:

 // equivalent template definition

 template <class Glorp>

 int compare(const Glorp &v1, const Glorp &v2)

 {

 if (v1 < v2)return -1;

 if (v2 < v1)return 1;

 return 0;

 }

该代码定义的compare 模板与前面一样。能够给模板形參赋予的唯一含义是差别形參是类型形參还是非类型形參。

假设是类型形參。我们就知道该形參表示未知类型。假设是非类型形參。我们就知道它是一个未知值。

4. 模板形參作用域

模板形參的名字能够在声明为模板形參之后直到模板声明或定义的末尾处使用。模板形參遵循常规名字屏蔽规则。

与全局作用域中声明的对象、函数或类型同名的模板形參会屏蔽全局名字:

 typedef double T;

 template <class T> T calc(const T &a, const T &b)

 {

 // tmp has the typeof the template parameter T

 // not that of the global typedef

 T tmp = a;

 // ...

 return tmp;

 }

将T 定义为double 的全局类型型别名将被名为T 的类型形參所屏蔽,因此,tmp不是double 型。相反,tmp的类型是绑定到模板形參的随意类型。使用模板形參名字的限制用作模板形參的名字不能在模板内部重用。

 template <class T> T calc(const T &a, const T &b)

 {

 typedef double T; //error: rede clares template parameter T

 T tmp = a;

 // ...

 return tmp;

 }

这一限制还意味着模板形參的名字仅仅能在同一模板形參表中使用一次:

 // error: illegalre use of template parameter name V

 template <class V,class V> V calc(const V&, const V&) ;

当然,正如能够重用函数形參名字一样,模板形參的名字也能在不同模板中重用:

// ok: reuses parameter type name across different templates

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

 template <class T> int compare(const T&, const T&) ;

5. 模板声明

像其它随意函数或类一样。对于模板能够仅仅声明而不定义。

声明必须指出函数或类是一个模板:

 // declares compare but does not define it

 template <class T> int compare(const T&, const T&) ;

同一模板的声明和定义中。模板形參的名字不必同样。

 // all three uses of calc refer to the same function template

 // forward declarations of the template

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

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

 // actual definitionof the template

 template <class Type>

 Type calc(const Type& a, const Type& b) { /* ... */ }

每一个模板类型形參前面必须带上keyword classtypename,每一个非类型形參前面必须带上类型名字,省略keyword或类型说明符是错误的:

 // error: must precede U by either typename or class

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

6. typename 与 class 的差别

在函数模板形參表中,keywordtypename 和class 具有同样含义,能够互换使用。两个keyword都能够在同一模板形參表中使用:

 // ok: no distinction between typename and class in template parameter list

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

使用keywordtypename 取代keywordclass 指定模板类型形參或许更为直观。毕竟。能够使用内置类型(非类类型)作为实际的类型形參,并且,typename更清楚地指明后面的名字是一个类型名。可是,keywordtypename 是作为标准C++ 的组成部分增加到C++ 中的,因此旧的程序更有可能仅仅用keywordclass。

7. 编写泛型代码的两个重要原则:

• 模板的形參是const 引用。

 

• 函数体中的測试仅仅用< 比較。

8. 类模板形參是必需的

想要使用类模板,就必须显式指定模板实參:

 Queue qs;                 // error:which template instantiation?

类模板不定义类型,仅仅有特定的实例才定义了类型。特定的实例化是通过提供模板实參与每一个模板形參匹配而定义的。

模板实參在用逗号分隔并用尖括号括住的列表中指定:

 Queue<int> qi;         // ok: defines Queue that holds ints

 Queue<string>qs;  // ok: defines Queue that holds strings

9. 类型形參的实參的受限转换

考虑以下的compare 调用:

 short s1, s2;

 int i1, i2;

 compare(i1, i2);     // ok: instantiate compare(int, int)

 compare(s1, s2);   // ok: instantiate compare(short, short)

一般而论。不会转换实參以匹配已有的实例化,相反,会产生新的实例。除了产生新的实例化之外,编译器仅仅会运行两种转换:

•const 转换:接受const 引用或const 指针的函数能够分别用非const对象的引用或指针来调用,无须产生新的实例化。假设函数接受非引用类型,形參类型实參都忽略const,即。不管传递const 或非const 对象给接受非引用类型的函数,都使用同样的实例化。

• 数组或函数到指针的转换:假设模板形參不是引用类型。则对数组或函数类型的实參应用常规指针转换。数组实參将当作指向其第一个元素的指针,函数实參当作指向函数类型的指针。

比如,考虑对函数fobj 和fref 的调用。

fobj函数复制它的形參,而fref的形參是引用:

 template <typename T> T fobj(T, T); // arguments are copied 

 template <typename T> T fref(const T&,const T&); // reference arguments

 string s1("avalue");

 const strings2("another value");

 fobj(s1, s2);       // ok:calls f(string, string), const is ignored

fref(s1, s2);        // ok: non const object s1 converted to const reference

 int a[10], b[42];

 fobj(a, b);          // ok:calls f(int*, int*)

 fref(a, b);           // error:array types don't match; arguments aren't converted to pointers

第一种情况下。传递string 对象和const string 对象作为实參,即使这些类型不全然匹配,两个调用也都是合法的。

在fobj 的调用中,实參被复制,因此原来的对象是否为const 无关紧要。在fref 的调用中,形參类型是const引用,对引用形參而言,转换为const 是能够接受的转换,所以这个调用也正确。

在另外一种情况中,将传递不同长度的数组实參。fobj的调用中。数组不同无关紧要,两个数组都转换为指针,fobj的模板形參类型是int*。可是。fref的调用是非法的,当形參为引用时数组不能转换为指针,a和b 的类型不匹配,所以调用将出错。

10. 类型转换的限制仅仅适用于类型为模板形參的那些实參。

原文地址:https://www.cnblogs.com/gccbuaa/p/6702405.html