新手发帖,很多方面都是刚入门,有误错的地方请大家见谅,欢迎批评指正
temlate模板
数函模板的声明
>建创一个通用的数函, 持支多种不同的形参, 防止重载数函的数函体复重计设, 把数函应用的数据类型作为参数;
template<typename 数据类型参数标识符> <返回类型><数函名>(参数表) { 数函体 }
>template是定义模板数函的关键字; typename(或class)是声明数据类型参数标识符的关键字; 用以说明它面后的标识符是数据类型标识符;
>数函模板声明白一个数函的描述, 不是一个可以直接行执的数函, 只有根据实际情况用实参的数据类型替代类型参数标识符后才能发生真正的数函;
>关键字typename可以用class替代, 数据类型标识符可以应用全体C++数据类型;
数函模板的生成
>数函模板的类型参数标识符是一个类型形参, 在应用时要将形参例实化为定确的数据类型, 例实化的的参数称为模板实参, 数函称为模板数函;
1) 数函模板许允应用多个类型参数, 但在定义部份个每形参前必须有关键字typename或class;
template<class 数据类型参数标识符1,…,class 数据类型参数标识符n> <返回类型><数函名>(参数表) { 数函体 }
2)在template句语与数函模板定义句语<返回类型>之间不许允有别的句语;
3)模板数函类似于重载数函, 区分: 数函重载时, 个每数函体内可以行执不同的动作; 但统一个数函模板例实化后的模板数函都必须行执同相的动作;
数函模板异常处置
>数函模板中的模板形参可例实化成各种类型, 但当例实化模板形参的各模板实参之间不全完分歧时, 会涌现误错;
template <typename T> void min(T &x, T &y) { return(x<y)?x:y; } void func(int i, char j) { min(i, i); min(j, j); min(i, j); min(j, i); }
误错 在用调时, 编译器按先最碰到的实参的类型隐含地生成一个模板数函, 并用它对全体模板数函行进分歧性检查; 例如对句语 min(i, j); 先碰到的实参i是整型的 编译器就将模板形参解释为整型, 此后涌现的模板实参j不能解释为整型而发生误错, 此时没有隐含的类型转换功能;
>C++中, 数函模板与同名的非模板数函重载时, 应遵守列下用调准则:
-找寻一个参数全完配匹的数函, 若找到就用调它; 若参数全完配匹的数函多于一个, 则这个用调是一个误错的用调.
-找寻一个数函模板, 若找到就将其例实化生成一个配匹的模板数函并用调它.
-若面上两条都失败, 则应用数函重载的法方, 通过类型转换发生参数配匹, 若找到就用调它.
-若面上三条都失败, 还没有找都配匹的数函, 则这个用调是一个误错的用调.
Note 绝大多数C++编译器不持支将模版类/模版数函的声明与实现开分. 全体一同写在头件文中, 不要开分写到两个件文中;
<refer to> http://blog.csdn.net/beyondhaven/article/details/4204345
---End---
模板偏化和特偏化
模板的定义
1 类模板
>定义一个栈的类模板, 可以用来纳容不同的数据类型;
template <class T> class stack { private: list* top; public: stack(); stack(const stack&); ~stack(); void push(T&); T& pop(); //… };
>template告知编译器这是模板, <class T>指明模板参数, 可以有一个或多个, 体具实现由用户指定, 关键字class可以用typename替代;
>类模板的应用除了要在声明时指明参数模板, 其余与通普类同相; e.g.
stack<int> int_stack; stack<char> ch_stack; stack<string> str_stack; int_stack.push(10); ch_stack.push(‘z’); str_stack.push(“c++”);
2 数函模板
>定义一个max数函返回统一类型(种这类型许允比拟)两个值的最大值;
template<class T> T mymax(const T& t1,const T& t2) { return t1 < t2 ? t2 : t1; }
>template <class T>的意思与类模板定义中同相;
>模板数函的应用和通普数函应用同相, 因为模板数函的参数可以从其传入参数中析解出来; e.g.
int highest = mymax(5,10); //析解出模板数函参数为int char c = mymax(‘a’, ’z’); //析解出模板数函的参数为char
3 模板的特化
>给模板中的全体模板参数一个体具的类;
1)类模板特化
>时有为了须要, 针对特定的类型, 须要对模板行进特化, 即殊特处置; e.g. stack模板针对bool类型, 因为bool只须要一个二进制位便可以对其行进存储, 应用一个字或者一个字节都是费浪存储空间;
template <class T> class stack {}; template < > //告知编译器这是一个特化的模板 class stack<bool> { //…// };
2)数函模板特化
int highest = mymax(5,10); char c = mymax(‘a’, ’z’); const char* p1 = “hello”; const char* p2 = “world”; const char* p = mymax(p1,p2);
>面前两个mymax准确, 第三个不能返回准确结果, 因为此时mymax直接比拟两个指针, 而不是指针向指的内容;
>当参数类型为const char*时的特化:
template <class T> T mymax(const T t1, const T t2) { return t1 < t2 ? t2 : t1; } template <> const char* mymax(const char* t1,const char* t2) { return (strcmp(t1,t2) < 0) ? t2 : t1; }
4 模板的偏特化
>给模板中的部份模板参数以体具的类, 残余的模板参数仍然是一来原的泛化定义;
>须要根据模板的某些但不是全体的参数行进特化;
>当你例实化一个模板时, 编译器会把现在存在的偏特化模板和全特化模板做比拟, 找出其中最合适, 最配匹的实现;
1)类模板的偏特化
>stl中的类vector定义:
template <class T, class Allocator> class vector { // … // }; template <class Allocator> class vector<bool, Allocator> { //…//};
这个例子中, 一个参数被绑定到bool类型, 另一个参数仍未绑定, 须要由用户指定;
2)数函模板的偏特化
Note 严格来说,数函模板不持支特偏化, 但由于可以对数函行进重载, 所以可以到达类似于类模板偏特化的效果;
a) template <class T> void f(T); 对a)行进重载: b) template <class T> void f(T*);
如果a)称为基模板, 那b)称为对基模板a)的重载, 而非对a)的特偏化;
Note 类模板class template能被全特化fully specialized或偏特化partially specialized, 数函模板只能被全特化; 由于数函模板可以重载, 可以通过重载实现偏特化的功能;
5 模板特化时的配匹规矩
1)类模板的配匹规矩
>最特化的优于次特化的, 模板参数最精确配匹的拥有最高的优先权;
template <class T> class vector{//…//}; // (a) 通普型 template <class T> class vector<T*>{//…//}; // (b) 对指针类型特化 template <> class vector <void*>{//…//}; // (c) 对void*行进特化
个每类型都可以用作通普型(a)的参数, 但只有指针类型才能用作(b)的参数. 只有void*才能作为(c)的参数;
2)数函模板的配匹规矩
>非模板数函拥有最高的优先权; 如果不存在配匹的非模板数函, 那么最配匹的和最特化的数函拥有高优先权;
template <class T> void f(T); // (d) template <class T> void f(int, T, double); // (e) template <class T> void f(T*); // (f) template <> void f<int> (int) ; // (g) void f(double); // (h) bool b = false; int i = 1; double d = 2.0; f(b); // 以 T = bool 用调 (d) f(42,d) // 以 T = int 用调(e) f(&i) ; // 以 T = int* 用调(f) f(d); // 用调(h)
<refer to> http://blog.csdn.net/zhang810413/article/details/1948603
---End---
关于数函模板特化, 有个趣有的例子:
template <class T> void fuc(T t) {cout<<"1"<<endl;} template <class T> void fuc(T* pt) {cout<<"3"<<endl;} template <> void fuc(int* pi) {cout<<"2"<<endl;} //--- int *pi = new int(1); fuc(pi);
输出是什么? 结果是2;
template <class T> void fuc(T t) {cout<<"1"<<endl;} template <> void fuc(int* pi) {cout<<"2"<<endl;} template <class T> void fuc(T* pt) {cout<<"3"<<endl;}
如果把第二第三行换交, 结果就变成了3;
Note: Specializations don't overload,only the base templates overload;
重载析解只选择基模板(或者非模板)数函, 当编译器选择了那个合适的基模板数函, 才会继承往下找合适的特化本版;
>原作者给出了一个计划: 数函模板用调类模板成员数函, 只特化类模板, 绕过了数函模板的这个阱陷:
//base template class, template <class T> struct FuncImpl { //users, go ahead and specialize this static int apply(const T & t) { return 0 ; } }; //partial specialazation for int template <> struct FuncImpl<int*> { static int apply(int* t) { return 1 ; } }; //partial specialazation for T* template <class T> struct FuncImpl<T *> { static int apply(T * t) { return 2 ; } }; //users, don't touch this! template <class T> int func(const T & t) { return FuncImpl<T> ::apply(t); } //--- int i = 10; cout<<func('c'); //r = 0 cout<<func(8); //r = 1 cout<<func(&i); //r = 2
这是个很安全的法方, 但是如果你比拟懒, 认为这个计划很费代码的话, 就要当心应用数函模板的特化: 先选择合适的重载的模板数函, 再去扩展它的特化本版;
<refer to> http://www.cppblog.com/ant/archive/2007/08/30/31201.html
---End---
文章结束给大家分享下程序员的一些笑话语录: 关于编程语言
如果 C++是一把锤子的话,那么编程就会变成大手指头。
如果你找了一百万只猴子来敲打一百万个键盘,那么会有一只猴子会敲出一 段 Java 程序,而其余的只会敲出 Perl 程序。
一阵急促的敲门声,“谁啊!”,过了 5 分钟,门外传来“Java”。
如果说 Java 很不错是因为它可以运行在所有的操作系统上,那么就可以说 肛交很不错,因为其可以使用于所有的性别上。