zoukankan      html  css  js  c++  java
  • C++笔记(3)模板与泛型编程

    3.1 函数模板

     1  
    2
    3 template <typename T>
    4
    5 inline int compare(const T &v1, const T &v2) //inline放在template之后
    6
    7 {
    8
    9 if (v1 < v2)
    10
    11 {
    12
    13 return -1;
    14
    15 }
    16
    17 if (v2 < v1)
    18
    19 {
    20
    21 return 1;
    22
    23 }
    24
    25 return 0;
    26
    27 }
    28
    29 string s1;
    30
    31 string s2;
    32
    33 compare(s1, s2) //用string 替代T创建compare.
    34
    35



    T表示的实际类型由编译器所用的函数而确定.

    使用函数模板时, 编译器会推断哪个模板实参绑定到模板形参,一旦编译器确定了实际的模板实参,就称它实例化了一个函数模板的实例, 实际上,编译器编写了一个函数实例.

     

    3.2 模板类

     

    关键字class or typename.

     1  
    2
    3 template <class Type> class tempclass
    4
    5 {
    6
    7 public:
    8
    9 tempclass();
    10
    11 Type func(void);
    12
    13 void func2(Type);
    14
    15 //...
    16
    17 private:
    18
    19 //...
    20
    21 };
    22
    23 tempclass<string> obj;
    24
    25 tempclass<vector<double>> obj;
    26
    27
    28
    29 typedef double T
    30
    31 template <typename T>
    32
    33 inline int compare(const T &v1, const T &v2){
    34
    35 T temp; /*将T定义为double的全局类型别名被T的类型形参所屏蔽,因此temp为绑定到模板形参的任意类型. */
    36
    37 //
    38
    39 }
    40
    41
    42
    43 template <typename T>
    44
    45 inline int compare(const T &v1, const T &v2){
    46
    47 typedef double T
    48
    49 T temp; //error, redeclares T
    50
    51 //
    52
    53 }
    54
    55



    模板可以只声明不定义, 且同一模板的声明和定义中,模板形参的名字可以不同.

     1 template <typename parm, typename u >
    2
    3 parm fcn(parm *array, U value)
    4
    5 {
    6
    7 parm::size_type *p; /*编译器会无法辨识是size_type或是数据成员,默认是数据成员,则重定义.*/
    8
    9 typename parm::size_type * p; //typename告诉编译器姜size_type当做类型.
    10
    11 }



     

    多个类型的实参必须完全匹配。

    short i(9);

    compare(i, 10); //error, ambiguous, compare(short, short), compare(int,int)

    如果允许常规转换,则可以定义

     1 template <typename A, typename B>
    2
    3 inline int compare(const A &v1, const B &v2){
    4
    5
    6
    7 }
    8
    9 short i(9);
    10
    11 compare(i, 10); //ok
    12
    13
    14
    15 template <typename T>
    16
    17 inline int compare(const T &v1, const T &v2);
    18
    19 int a[10],b[20];
    20
    21 compare(a, b); /*error,当形参为引用时,数组不能转换为指针,a和b的类型不匹配.*/
    22
    23
    24
    25 template <typename T>
    26
    27 inline int compare(const T v1, const T v2);
    28
    29 int a[10],b[20];
    30
    31 compare(a, b); /*ok,非引用形参,对数组或函数类型的实参,都用常规指针转换,指向数组第一个元素和指向函数. */
    32
    33
    34
    35 int (*p)(const int&, const int&) = compare; //实例化compare(const int&, const int&);
    36
    37



    在返回类型中使用形参。

    1 template < typename C ,typename A, typename B>
    2
    3 inline C compare(const A &v1, const B &v2);
    4
    5 int i = 9;
    6
    7 short s = 10;
    8
    9 long l = compare<long>(i, s);



    模板实参从左至右与与对应模板形参相匹配,只有最右边形参的显示模板实参可以忽略。

     

     1 //如果定义
    2
    3 template <typename A ,typename B, typename C>
    4
    5 inline C compare(const A &v1, const B &v2);
    6
    7 //必须像是指模板形参
    8
    9 long l =cmpare< int, short, long>(i, s);
    10
    11 long l = compare<long>(i, s); //error, long给了A
    12
    13
    14
    15 void func(int (*)(const int &, const int &));
    16
    17 void func(string (*)(const string &, const string &));
    18
    19 func(compare); //error, ambiguous
    20
    21 func(compare<int>); //ok,显示指定模板参数
    22
    23



    普通函数只需要在源文件中声明,而定义类对象时,类定义必须可用,所以函数声明和类定义放在头文件中。

    编译器实例化的时候,必须要能够访问函数模板定义和类模板定义,

    包含编译模型

    xxx.h

     1 #ifndef xxx
    2
    3 #define xxx
    4
    5 template <typename T>
    6
    7 inline int compare(const T v1, const T v2);
    8
    9 #include "xxx.cc"
    10
    11 #endif



     

    xxx.cc

    1 template <typename T>
    2
    3 inline int compare(const T v1, const T v2)
    4
    5 {
    6
    7 }



     

    分别编译模型

    xxx.cc

    1 export template <typename T>
    2
    3 inline int compare(const T v1, const T v2);
    4
    5 #include "xxx.h"



     

    xxx.h

    1 template <typename T>
    2
    3 inline int compare(const T v1, const T v2)
    4
    5 {
    6
    7 }
    8
    9



    类声明必须放在头文件中,头文件中的类定义体中不应该使用export关键字,如果在头文件中使用了export,则该头文件中只能被程序中的一个源文件使用。

    xxx.h

     1 template <class Type> class tempclass
    2
    3 {
    4
    5 public:
    6
    7 tempclass();
    8
    9 Type func(void);
    10
    11 void func2(Type);
    12
    13 //...
    14
    15 private:
    16
    17 //...
    18
    19 };
    20
    21



    xxx.cc

    1 export template <class Type> class tempclass;
    2
    3 #include "xxx.h"



     

    3.3 类模板成员函数

     

    xxx.cc

    1 template <class type> void tempclass<type>::func2(type)
    2
    3 {
    4
    5 }



     

    3.4 类模板友元

     1 template <class Type> class tempclass
    2
    3 {
    4
    5 public:
    6
    7 tempclass();
    8
    9 Type func(void);
    10
    11 void func2(Type);
    12
    13 friend class friendclass;
    14
    15 friend void friendfunc(); /*普通友元,可以访问tempclass的任意实例的private和protected成员 */
    16
    17 template <class T> friend friendclass2;
    18
    19 template <class T> friend void friendfunc2(void);
    20
    21 /* 一般模板友元关系,模板类friendclass2和模板函数friendfunc2的任何实例都可以访问任何tempclass的任意实例的私有成员. */
    22
    23 //...
    24
    25 private:
    26
    27 //...
    28
    29 static std::size_t ctr;
    30
    31 };
    32
    33 template<class type> size_t tempclass<type>::ctr = 0;



     

    类模板的模板友元函数定义有2种方式:
    1.
    将友元模板函数直接定义在类模板中。这种方式比较简单直接。

     1 template <typename T>class Number;
    2
    3 template <typename T> void print(const Number<T>& n);
    4
    5
    6
    7 template <typename T>
    8
    9 class Number {
    10
    11 public:
    12
    13 Number(T v){}
    14
    15 friend void print(const Number& n)
    16
    17 {
    18
    19 }
    20
    21 };
    22
    23 Number<int> n(1);
    24
    25 print(n);




    2.
    将友元模板函数声明在类模板中,定义在类模板之外。这种方式的写法,如果不小心,通常会出现编译没问题,链接时无法解析的错误。

     1 template <typename T>class Number;
    2
    3 template <typename T> void print(const Number<T>& n);
    4
    5
    6
    7 template <typename T>
    8
    9 class Number {
    10
    11 public:
    12
    13 Number(T v){}
    14
    15 friend void print<T>(const Number<T>& n);
    16
    17 };
    18
    19 template <typename T>void print<T> (const Number<T>& n) {}
    20
    21 Number<int> n(1);
    22
    23 print(n);



     

    特定的模板友元关系

     1 template <class type> class foo; //必须先声明
    2
    3 template <class type> void func(const type&);
    4
    5 template <class Type> class tempclass
    6
    7 {
    8
    9 public:
    10
    11 friend class foo<char *>;
    12
    13 friend void func<char *>(char * const &);
    14
    15 friend class foo<type>;
    16
    17 friend void func<type>(const type &);
    18
    19 private:
    20
    21
    22
    23 };



     

    3.5 函数模板特化

     

    一个或多个模板形参的实际类型或实际值是指定的,特化的声明必须与模板相匹配.

    使用模板特化的文件必须包含模板特化的声明.

     1 template <>
    2
    3 int compare<const char*>(const char * const &v1, const char * const &v2)
    4
    5 {
    6
    7 return strcmp(v1, v2);
    8
    9 }
    10
    11 int a = 2, b = 3;
    12
    13 const char *cp1 = "a", *cp2 = "b";
    14
    15 compare(a, b); //calls the generic version instantiated with int
    16
    17 compare(cp1, cp2); // calls the specialization
    18
    19
    20
    21 template <typename T> int compare(const T&v1, const T&v2)
    22
    23 {
    24
    25 if (v1 < v2) return -1;
    26
    27 if (v2 < v1) return 1;
    28
    29 return 0;
    30
    31 }
    32
    33 /* template <> int compare<const char*>(const char * const &v1, const char * const &v2); 声明放这则OK. */
    34
    35 int _tmain(int argc, _TCHAR* argv[])
    36
    37 {
    38
    39 const char *cp1 = "a", *cp2 = "b";
    40
    41 compare(cp1, cp2); /*无法编译, explicit specialization; 'int compare<const char*>(const T &,const T &)' has already been instantiated */
    42
    43 return 0;
    44
    45 }
    46
    47
    48
    49 template <> int compare<const char*>(const char * const &v1, const char * const &v2)
    50
    51 {
    52
    53 return strcmp(v1, v2);
    54
    55 }
    56
    57



    3.6 类模板特化

     

     1 template <> class tempclass<const char*>
    2
    3 {
    4
    5 public :
    6
    7 void func2(const char *);
    8
    9 };
    10
    11 void tempclass<const char*>::func2(const char * v)
    12
    13 {
    14
    15 }



     

    3.7 类成员特化

     

    xxx.h

     1 template <class Type> class tempclass
    2
    3 {
    4
    5 public :
    6
    7 int compare(const Type&v1, const Type&v2);
    8
    9 };
    10
    11 int tempclass <const char *>::compare(const char * const &v1, const char * const &v2);



    xxx.cc

     1 template <class Type>
    2
    3 int tempclass<Type>::compare(const Type &v1, const Type &v2)
    4
    5 {
    6
    7 if (v1 < v2) return -1;
    8
    9 if (v2 < v1) return 1;
    10
    11 return 0;
    12
    13 }
    14
    15
    16
    17 template <>
    18
    19 int tempclass <const char *>::compare(const char * const &v1, const char * const &v2)
    20
    21 {
    22
    23 return strcmp(v1, v2);
    24
    25 }
    26
    27



    3.8 类模板的部分特化

     

     1 template <class T1, class T2> class some_tempclass
    2
    3 {
    4
    5 };
    6
    7 template <class T1> class some_tempclass<T1, int>
    8
    9 {
    10
    11 };
    12
    13 some_tempclass<int, string> obj; //use template <class T1, class T2> class some_tempclass
    14
    15 some_tempclass<string, int> obj2; //use template <class T1> class some_tempclass<T1, int>



     

    3.9 重载和函数模板

     

     1 template <class T>
    2
    3 int compare(const T &v1, const T &v2);
    4
    5 template <class T1, class T2>
    6
    7 int compare(const &T1, const &T1, const &T2);
    8
    9 int compare(const char * const &v1, const char * const &v2);
    10
    11
    12
    13 const char *cp1 = "a", *cp2 = "b";
    14
    15 compare("a", "b"); /*call int compare(const char * const &v1, const char * const &v2); 普通函数优先级比函数模板更高. */
    16
    17 compare(1, 2); //call int compare(const T &v1, const T &v2);
    18
    19 compare(1, 1, 2); //call int compare(const &T1, const &T1, const &T2);
    20
    21 char *cp3 = "a", *cp3 = "b"; /*call int compare(const T &v1, const T &v2); 因为调用普通函数需要从char *转换为const char * */


  • 相关阅读:
    C#磁吸屏幕窗体类库
    准备
    我写的诗
    How to turn off a laptop keyboard
    How to tell which commit a tag points to in Git?
    Why should I care about lightweight vs. annotated tags?
    How to get rid of “would clobber existing tag”
    Facebook, Google and Twitter threaten to leave Hong Kong over privacy law changes
    The need for legislative reform on secrecy orders
    Can a foreign key be NULL and/or duplicate?
  • 原文地址:https://www.cnblogs.com/zengyou/p/2195586.html
Copyright © 2011-2022 走看看