C++ Templates读书笔记(1-12章)

1410阅读 0评论2014-01-19 automation_mb
分类:C/C++

 

第一部分 模板基础

2章:函数模板

1. 在声明引入类型参数的时候, 不能使用struct代替typename p10

2. 目前,函数模板不能指定缺省的模板实参 p13

3. 作为返回值得类型参数,必须显式指定; p14

4. 注意使用引用解决临时变量作为返回值的问题; p17

5. 一定要让函数重载的所有版本的声明位于调用之前。 p19

3章: 类模板

1. 何时用stack何时用只用stack?前者表示类的类型, 后者表示类名。 p23

2. 只有被调用的类模板成员才会产生函数的实例化代码。 p26

 

4章: 非类型模板参数

1. 函数模板被看成用于命名一组函数重载的集合,该集合不能用于模板参数的演绎,所以必须将这个函数模板的实参强制转换

成具体类型。 p37 **

2. 浮点数和类对象是不允许作为非类型模板参数的。p37

3. 全局指针不能作为类的非类型模板参数。p38

4. 具有外部链接属性的全局数组可以作为类的非类型模板参数。p37

5章: 技巧性基础知识

1. C++标准化过程中,引入typename是为了说明:模板内部的标识符可以是一个类型;p39

2. .template or ->template 表示调用成员模板依赖于外部的模板实参时,区分后面的<是模板实参的起始符号而不是小于号。 p41 *

3. 非依赖型名称会立即查找,但是模板是用到时才实例化,所以非依赖型名称不会在依赖型基类中进行查找。但可以通过this-> OR Base:: 限定符去延迟查找。  p41 p132

4. 函数模板支持模板的模板参数。 p47

5. 当把模板的模板参数定义为一个类时,不能用typename替换class p47

6. 把字符串当做模板的类型实参会出现意外的结果, const char[5] & const char[6]是不同的类型。 p52

7. 对于字符串,在实参演绎过程中,当且仅当参数不是引用时,才会出现数组到指针的类型转换,成为decay p55

6章: 模板实战

1. 编译器必须知道: 应该实例化哪个定义和要基于哪个模板实参进行实例化。所以在使用分离模型时会出现如下情况:

看到调用时不知道定义是什么;看到定义时确又不知道基于什么实参进行实例化  p59

2. 1所述问题可以通过显示实例化进行解决; 及在类的定义之后加上 template Stack::func(); p 61

3. 可以在模板的声明和定义式前加上export,显示实例化。 p63 *

4. 预编译头文件 P68 ***

5. 模板调试 P70 ***

7章: 模板术语

1. 类模板 ,函数模板; P83

2. 实例化, 特化。 p84

3. 一处定义原则- ODR  p86

4. 模板参数, 模板实参 - 显式替换 隐式替换。 p87

5. 模板实参必须是一个可以在编译器确定的模板实体或值。 p87

第二部分 深入模板

8章: 深入模板基础

1. 联合(Union)模板也是允许的 template union C{}; p93

2. 缺省调用实参可以依赖于模板参数。p93

3. 成员模板不能被声明为虚函数,因为实例化的个数要等到整个程序翻译完才能知道,而虚函数表的大小应该是固 定的。 p94

4. 类模板不能和另一个实体拥有一个相同的名字,这一点不同于普通类。 p95

5. 模板名字是具有链接的, 但是他们不能具有C链接,及extern "C"非法。 p95

6. 模板通常具有外部链接,唯一的例外就是前面有static修饰的函数模板。 p96

7. 非类型模板参数包括:整形或枚举,指针类型,引用类型。p97

8. 函数和数组在指定为模板参数前会隐式转换成指针类型。p98

9. 非类型模板参数智能是右值,不能被取址,不能被赋值。p98

10.模板的模板参数是代表类模板的占位符, 不能使struct or union关键字。p98

11.模板的模板参数可以具有缺省参数,但是只有在实参没有指定的情况下才会应用。 p98

12.模板的模板参数的名称,只能被自身其它参数声明所使用,一般用不到可以省略。 p99

13.目前只有类模板可以声明缺省的模板实参,函数模板则不行,缺省值可以在前面的几个声明中提供,但要注意顺序,且不能重复声明缺省实参。p100

14.template-id  :  模板名称+<实参列表>  p100

15.注入式类名称: 在拥有模板参数P1, P2的类模板X的作用域内,模板名称X等同于他的Template-id;  p100

16.显式指定的模板参数会阻止该模板参数的演绎。 p101

17.函数模板的返回值模板参数,永远得不到演绎,所以需要显式指定。p101

18.SFINAEsubstitution failure is not an error)替换失败并不是一个错误。p102

19.SFINAE保护原则:试图创建无效的类型,但是并不允许试图计算无效的表达式,如:p103

template void f(int (&)[24/4-I])

template void f(int (&)[24/4+I])

int main(){ &f<4> };

20.局部类和局部枚举不能作为模板的类型实参。p103

21.未命名的class类型或者未命名的枚举类型不能作为模板的类型实参。如:

typedef enum{ red, green } *ColorPtr;

List error; // 因为typedef定义的是*ColorPtr 而不是 ColorPtr p104 **

22.非类型模板参数只包括:

 1) 某一个具有正确类型的非类型模板实参

 2) 一个编译器期整形、枚举常值。类型需要能够匹配,或者可以隐式类型转换。

 3) 前面有单目运算符&的外部变量或者函数名称。其中函数和数组的&可以省略。

 4) 对于引用型的非类型模板参数,前面没有&的外部变量和外部函数也是可取的。

 5) 一个指向成员的指针常量(pointer-to-member constant);类似于&C::mp105 **

26.类的静态成员是可取的外部变量和函数名称。 p106

27.不能作为模板非类型实参的包括

 1) 空指针常量。

 2) 浮点型常量

 3)字符串  p106

28.几个error

 1) 派生类到基类的类型转换不考虑。

 2) 域运算符(.)后面的变量不会被看成常量。

 3) 单一数组的地址是不可取的。 p107

29.“模板的模板参数”必须是一个类模板,所以只能用class定义typep107

30.模板的模板实参的缺省的模板实参不予考虑; p107

31.模板的模板参数的缺省的模板实参是被考虑的;p107

32.对于用关键字class声明的模板类型参数,我们可以用满足条件的任何类型作为它的替换实参,struct union等等。p108

33.成员模板不可能是一个虚函数;p109

34.构造函数模板一定不是一个默认的构造函数。 p109

35.从函数模板实例化出来的函数一定不是一个普通函数。 p109 **那全特化呢?

36.友元的首次声明在类模板中,则它在该类的外围域不可见。这点不同于普通类。 p110

37.通过确认紧跟在友元函数名称后面的一对尖括号,我们可以把函数模板的实例声明为友元。 p110

38.如果名称不是受限的,那么该名称不能引用一个模板(没有尖括号),如果友元声明的地方匹配不到普通函数,则该声明为首次声明,此时可以具有定义; p111

39.如果名称是受限的,该名称必须引用一个之前位置的函数模板或者普通函数,优先匹配模板。且不能出现定义。p111

40.在模板内部定义的友元函数类型定义中,必须包含类模板的模板参数,以防止重定义。p112

41.由于函数的实体定义在类内部,所以这些函数是内联的,因此两个不同的翻译单元可以生成相同的函数。p113

42.可以声明友元模板。只有在友元模板的声明是一个(1)非受限(2)后面没有尖括号的情况下,才能出现定义。

9 模板中的名称

1. 两个概念:(1)受限名称 (2)依赖名称p115

2. 名称的分类(1)标识符Identifier 2)运算符ID Operator-function-id 3)类型转换ID Conversion-function-id (4)模板ID Template-id 5)非受限ID Unqualified-id (6)受限ID Qualified-id 7)受限名称 Qualified-Name 8)非受限名称 Unqualified-Name (9) 依赖型名称 Dependent name 10)非依赖型名称 Nondependent name . p116

3. 受限名称的查找在一个受限的作用域内,如果该作用域是一个类,查找范围可以达到它的基类。 P117

4. 非受限名称的查找会在所有外围类中逐层进行。P118

5. ADL argument-dependent lookup p118

6. 不适用ADL的情况, 受限名称,调用函数用括号括起来;对于成员函数或者类型名称,普通函数能找到。P119

7. 非受限名称后面的括号里有一个或多个表达式,那么ADL会查找其实参的associated classassociated namespacep119

8.关于associated class associated namespace

1) 对于基本类型,该集合为空

2)对于指针和数组类型,该集合是他们所引用类型的associated calss associated namespace

3)对于枚举类型,associated namespace指的是枚举类型所在的namespace 对于类成员,associated class指的是该类。  **包括全局namespace 包括基类?

4)对于class类型, associated class集合包括:该class本身,他的外围类型,直接基类和间接基类。Associated namespace包括该类所在的namespace。如果该类是某个类模板的实例,还包括该类模板声明所在的class namespace

)对于函数类型,该集合包括函数参数和返回值的associated class associated namespace

6)对于类X的成员指针包括,该成员相关的 associated class associated namespace X associated class associated namespace  P119

9. ADL忽视using-directiveP120 **

10.友元函数的初次声明在类中,则其声明在外围类作用域中不可见,但是通过ADL可以使它可见,使用ADL之后小心重定义。 P121

11.非受限名称后面没有紧跟模板实参,是不会被看成是模板名称的。解决办法是给他加上作用域限定符::   p123

12.maximum munch扫描原则。 P125***

13.typename使用:

1)名称出现在一个模板中

2)名称是受限的。

3)名称不是用于指定基类继承的列表中,也不是位于引入的构造函数成员初始化列表中。

4)名称依赖于模板参数。(指定必须添加typename还是可省略) p126

14.如果限定符前面的名称依赖于某个模板参数,且后面紧跟的是一个template-id,那么就需要使用template P128

15. 使用using-declaration引入名字空间不会涉及到上下文的问题。P129

16. 使用using-declaration引入类能力是有限的,只能引入基类中的名称,有点类似于快捷方式。P129

17. 如果使用using-declaration引入的依赖型名称是一个类型,则必须使用typename关键字,如: using typename BXT::Mystery;     p130

18. 关于显示模板实参和ADL 编译器会把 <>看做小于号和大于号,因为无法判断id一个template-id   p130

19.对于模板中的非依赖型基类,如果在他的派生类中查找一个非受限名称,它会先查找这个非依赖基类,然后再查找模板的实参列表。 P131

20.非依赖型名称会在看到时立即查找,但是不会在基类中进行查找。 P132

21.可以通过将非依赖型名称变为一个依赖型名称,来延迟该名称的查找。 this-> 或者 C::  p133

11  模板的实参演绎

1.       对于匹配类型A ,和参数化类型P

a.       如果被声明的参数是一个引用,那么P就是所引用的类型,A仍然是实参的类型。

b.       如果被声明的类型不是一个引用,P就是所声明的类型,A仍然是实参的类型。

c.       若果这个参数类型是数组或者函数类型,还会进行decay转型,转化为指针类型;同时还会忽略高层次的constvolatile限定符。 P164 **

2.       对于引用类型,是不会进行decay转型的。例如:

Template T const& max( T const& a, T const& b);

Max( “Apple” , “Pear” ); // T 则被同时演绎成 char[6]char[5] ,  演绎失败! P165

3.       不能作为演绎上下文的包括:

a.       受限的类型名称

b.       模板参数还有其他成分的非类型表达式    p167  ****

4.       两种特殊情况:

a.       去函数模板地址。P为函数模板声明的参数化类型。A为函数指针指定的类型。

b.       档转型运算符模板。P为转型运算符返回的类型。A为试图转型的类型。 P167

5.       可接受的实参转型

a.       如果原来声明的参数是一个引用参数,那么被替换的P类型可以比A类型多一个const或者volatile.

b.       如果A类型是指针类型或者成员指针类型,那么他可以进行限定符转型,就是添加constVolatile,转化为被替换的P类型。

c.       当演绎过程不涉及到转型运算符石被替换的P类型可以使A类型的基类,或者指向A指向类的基类的指针。 P 168

6.       模板的实参演绎只能用户函数模板或者成员函数模板,不能应用于类模板。  P169

7.       缺省的函数模板实参不能作为实参演绎。 P170

8.       缺省的函数模板实参如果没有使用,则遵循SFINAE原则。 P170

9.       Barton-Nackman方法 **

12  特化与重载

1.       模板的特化与函数模板的重载,类模板不支持重载,函数不支持局部特化,但是重载可以替换该功能。 P177

2.       不仅同名模板可以同时存在,他们各自的实例化体也可以同时存在,即使他们拥有一样的参数和返回值。 P179

3.       函数签名:

a.       非受限函数名称(或者产生自函数模板的这类名称)。

b.       函数名称所属的类作用域或者名字空间作用域;如果函数名称是具有内部链接的,还包括该名称声明所在的翻译单元。

c.       函数的constvolatile或者const volatile限定符(前提是它是一个具有这类限定符的成员函数. **

d.       函数参数的类型(如果这个参数产生自函数模板,那么指的是模板参数被替换之前的类型 **

e.       如果这个函数产生自函数模板,那么包括他的返回类型。

f.        如果这个函数式产生自模板,那么包括模板参数和模板实参。 P180

4.       正式的排序原则  p183***

5.       模板函数可以和非模板函数同时重载,但是当其他条件都一样时,实际调用优先选择非模板函数。P185

6.       以前置声明的方式全特化模板,不需要template<>; p187

7.       应确认特化的声明对所有泛型模板的用户都可见。P189

8.       全局函数模板特化不能包含缺省的实参值,然而可以直接应用这些缺省实参值。P190

9.       对于非内联的全局函数模板特化,他的定义只能出现一次。(那么全局类特化呢)**P191

10.   全局成员特化 p192

11.   不同于普通类的成员函数和静态成员变量,针对于类模板的特化,非定义的类外声明在C++中是合法的。(目的是为了把定义放到单独的编译单元中)P193

12.   局部特化递归时,应该添加一个全特化作为终止点。P196

13.   局部特化参数列表和实参列表的一些约束:

a.       局部模板的实参必须和基本模板的相应参数是匹配的。

b.       局部特化的参数列表不能具有缺省参数;但局部特化仍然可以使用基本类模板的缺省参数。

c.       局部模板的非类型实参只能是非类型值,或者是普通的非类型模板参数,不能使依赖型表达式如:2*N *

d.       局部特化的模板参数列表不能和基本模板的参数列表完全相同。 P196

14.   多个匹配程度一样的局部特化会造成二义性。

15.   对于类模板局部特化的参数个数是可以和基本模板不一样的;既可以别基本模板多也可以比基本模板少。

 

上一篇:GDB调试小结
下一篇:没有了