C++ 模板笔记
1.函数模板可以用与非模板函数一样的方式声明为 inline。说明符放在模板形参表之后、返回类型之前,不能放在关键字 template 之前。
template <typename T> inline T min(const T&, const T&);
2.模板形参的名字可以在声明为模板形参之后直到模板声明或定义的末尾处使用。
模板形参遵循常规名字屏蔽规则。与全局作用域中声明的对象、函数或类型同名的模板形参会屏蔽全局名字:
typedef double T;
template <class T> T calc(const T &a, const T &b)
{
// tmp has the type of the template parameter T
// not that of the global typedef
T tmp = a;
// ...
return tmp;
}
3.对于模板可以只声明而不定义。声明必须指出函数或类是一个模板:
// declares compare but does not define it
template <class T> int compare(const T&, const T&) ;
4.每个模板类型形参前面必须带上关键字 class 或 typename,每个非类型形参前面必须带上类型名字,省略关键字或类型说明符是错误的:
// error: must precede U by either typename or class
template <typename T, U> T calc (const T&, const U&) ;
5.使用关键字 typename 代替关键字 class 指定模板类型形参也许更为直观,毕竟,可以使用内置类型(非类类型)作为实际的类型形参,而且,typename
更清楚地指明后面的名字是一个类型名
6.合法
typedef char Ctype ;
template <class Ctype> Ctype f5(Ctype a)
{
return a;
}
7.编写泛型代码的两个重要原则:
模板的形参是 const 引用。
函数体中的测试只用 < 比较。
8.
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("a value");
const string s2("another value");
fobj(s1, s2); // ok: calls f(string, string), const is ignored798
fref(s1, s2); // ok: non const object s1 converted to constreference
int a[10], b[42];
fobj(a, b); // ok: calls f(int*, int*)
fref(a, b); // error: array types don't match; arguments aren'tconverted to pointers
第一种情况下,传递 string 对象和 const string 对象作为实参,即使这些类型不完全匹配,两个调用也都是合法的。在 fobj 的调用中,实参被复制,
因此原来的对象是否为 const 无关紧要。在 fref 的调用中,形参类型是 const引用,对引用形参而言,转换为 const 是可以接受的转换,所以这个调用也正
确。
在第二种情况中,将传递不同长度的数组实参。fobj 的调用中,数组不同无关紧要,两个数组都转换为指针,fobj 的模板形参类型是 int*。但是,fref
的调用是非法的,当形参为引用时,数组不能转换为指针,a 和b 的类型不匹配,所以调用将出错。
template <typename T> T fobj(T, T){}; // arguments are copied
template <typename T>T fref(const T&a, const T&b){return a;}; // reference arguments
int _tmain(int argc, _TCHAR* argv[])
{
int a[10], b[10];
fref(a[10], b[10]);
return 0;
}
9.可以使用函数模板对函数指针进行初始化或赋值,这样做的时候,编译器使用指针的类型实例化具有适当模板实参的模板版本。
template <typename T> int compare(const T&, const T&);
// pf1 points to the instantiation int compare (const int&, const int&)
int (*pf1) (const int&, const int&) = compare;
10.类模板成员函数的定义具有如下形式:
必须以关键字 template 开关,后接类的模板形参表。
必须指出它是哪个类的成员。
类名必须包含其模板形参。
从这些规则可以看到,在类外定义的 Queue 类的成员函数的开关应该是:
template <class T> ret-type Queue<T>::member-name
11.在类模板中可以出现三种友元声明,每一种都声明了与一个或多个实体友元关系:
普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。
类模板或函数模板的友元声明,授予对友元所有实例的访问权。
只授予对类模板或函数模板的特定实例的访问权的友元声明。
12.在类模板中可以出现三种友元声明,每一种都声明了与一个或多个实体友元关系:
普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数。
类模板或函数模板的友元声明,授予对友元所有实例的访问权。
只授予对类模板或函数模板的特定实例的访问权的友元声明。
普通友元
非模板类或非模板函数可以是类模板的友元:
template <class Type> class Bar {
// grants access to ordinary, nontemplate class and function
friend class FooBar;
friend void fcn();
// ...
};
这个声明是说,FooBar 的成员和 fcn 函数可以访问 Bar 类的任意实例的private 成员和 protected 成员。
一般模板友元关系
友元可以是类模板或函数模板:
template <class Type> class Bar {
// grants access to Foo1 or templ_fcn1 parameterized by any type
template <class T> friend class Foo1;
template <class T> friend void templ_fcn1(const T&);
// ...
};
这些友元声明使用与类本身不同的类型形参,该类型形参指的是 Foo1 和temp1_fcn1 的类型形参。在这两种情况下,都将没有数目限制的类和函数设为
Bar 的友元。Foo1 的友元声明是说,Foo1 的友元声明是说,Foo1 的任意实例都可以访问 Bar 的任意实例的私有元素,类似地,temp_fcn1 的任意实例可以
访问 Bar 的任意实例。这个友元声明在 Bar 与其友元 Foo1 和 temp1_fcn1 的每个实例之间建立了一对多的映射。对 Bar 的每个实例而言,Foo1 或 temp1_fcn1 的所有实例都
是友元。
特定的模板友元关系
除了将一个模板的所有实例设为友元,类也可以只授予对特定实例的访问权:
template <class T> class Foo2;
template <class T> void templ_fcn2(const T&);
template <class Type> class Bar {
// grants access to a single specific instance parameterized by char*
friend class Foo2<char*>;
friend void templ_fcn2<char*>(char* const &);
// ...
};
声明依赖性
当授予对给定模板的实例的访问权时候,在作用域中不需要存在该类模板或函数模板的声明。实质上,编译器将友元声明也当作类或函数的声明对待。
想要限制对特定实例化的友元关系时,必须在可以用于友元声明之前声明类或函数:
template <class T> class A;
template <class T> class B {
public:
friend class A<T>; // ok: A is known to be a template
friend class C; // ok: C must be an ordinary, nontemplate class
template <class S> friend class D; // ok: D is a template
friend class E<T>; // error: E wasn't declared as a template
friend class F<int>; // error: F wasn't declared as a template
};
如果没有事先告诉编译器该友元是一个模板,则编译器将认为该友元是一个普通非模板类或非模板函数。
13.模板特化(template specialization)是这样的一个定义,该定义中一个或多个模板形参的实际类型或实际值是指定的。特化的形式如下:
(1).关键字 template 后面接一对空的尖括号(<>);
(2).再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参;
(3).函数形参表;
(4).函数体。
下面的程序定义了当模板形参类型绑定到 const char* 时,compare 函数的特化:
// special version of compare to handle C-style character strings
template <>
int compare<const char*>(const char* const &v1,const char* const &v2)
{
return strcmp(v1, v2);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。