模板是C++支持参数化多态的工具,模板的参数有三种类型:类型参数、非类型参数和模板类型参数。

用几个例子说明各个模板参数的使用方法:

类型参数:

由class或者typename标记的参数,称为类型参数。类型参数是使用模板的主要目的。

#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdio.h>
 
using namespace std;
 
template <class U,typename V=int>
void add(U &u,V &v){
    cout << u + v<< endl;
}
 
int main()
{
    int a=1,b=2;
    // 调用函数时指定非默认参数类型
    add<int>(a,b);
    double c = 0.5;
    // 覆盖默认参数类型 
    add<int,double>(a,c);
 
    std::cout << "--end--" << endl;
    return 0;
}

输出:

3
1.5
--end--
#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdio.h>
 
using namespace std;
 
template <class U,typename V=int>
class myclass{
public:
    void add(U &u,V &v){
        cout << u + v<< endl;
    }
};
 
int main()
{
    // 在实例化类时指定参数类型
    myclass<int> m;
    int a = 5,b = 2;
    m.add(a,b);
    // 覆盖默认参数类型 
    myclass<int,double> m2;
    double d = 0.5;
    m2.add(a,d);
 
    std::cout << "--end--" << endl;
    return 0;
}

输出:

7
5.5
--end--

非类型参数

非类型参数是指内置类型参数。
定义:

template<typename T, int a> 
class A 
{ 
}; 

上述代码中,int a就是非类型的模板参数,非类型模板参数为函数模板或类模板预定义一些常量,在模板实例化时,也要求实参必须是常量,即确切的数据值。需要注意的是,非类型参数只能是整型、字符型或枚举、指针、引用类型。非类型参数在所有实例中都具有相同的值,而类型参数在不同的实例中具有不同的值。
示例一:

#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdio.h>
 
using namespace std;
template <typename T,unsigned int len>
class MyString
{
private:
    T array[len];
public:
    // 构造函数
    MyString(){
        for(unsigned int i = 0;i < len;i++){
            this->array[i] = i + 1;
        }
    }
    // 对操作符 [ ] 重载
    T& operator[](unsigned int i){
        if(i >= len)return array[0];
        return this->array[i];
    }
};
 
int main()
{
    // 即类型模板参数需要指定参数类型,而非类型模板参数则需要指定具体数值
    MyString<unsigned int,5> ms1;
    cout << ms1[2] << endl;
 
    MyString<double,5> ms2;
    cout << ms1[3] << endl;
    std::cout << "--end--" << endl;
    return 0;
}

使用非类型参数时,有以下几点需要注意。
(1)调用非类型参数的实参必须是常量表达式,即必须能在编译时计算出结果。
(2)任何局部对象、局部变量的地址都不是常量表达式,不能用作非类型的实参,全局指针类型、全局变量也不是常量表达式,也不能用作非类型的实参。
(3)sizeof()表达式结果是一个常量表达式,可以用作非类型的实参。
(4)非类型参数一般不用于函数模板。

模板类型参数:

模板类型参数就是模板的参数为另一个模板。
定义:

template<typename T, template<typename U, typename Z> class A> 
class Parameter 
{ 
    A<T,T> a; 
};

上述代码中,类模板Param eter的第二个模板参数就是一个类模板。需要注意的是,只有类模板可以作为模板参数,参数声明中必须要有关键字class。

// 例子确实写的比较绕,知道怎么回事就可以了
#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdio.h>
using namespace std;
 
template <class T,class U>
class myclass
{
public:
    T _t;
    U _u;
    myclass(){
        cout << "myclass init 1" << endl;
    }
    myclass(T &t,U &u):_t(t),_u(u){
        cout << "myclass init 2" << endl;
    }
    ~myclass(){
        cout << "myclass delete" << endl;
    }
};
template <typename T,template<typename U,typename Z> class myclass>
class OtherClass{
public:
    // 引用构造实例化 _m 对象
    myclass<T,T> _m;
    OtherClass(myclass<T,T> &m):_m(m){
    }
    void show(){
        cout << _m._t << endl;
        cout << _m._u << endl;
    }
};
 
int main()
{
    int a = 5;
    int b = 6;
    myclass<int,int> m(a,b);
    printf("after myclass!\n");
    OtherClass<int,myclass> o(m);
    printf("after otherclass!\n");
    o.show();
 
    std::cout << "--end--" << endl;
    return 0;
}

输出:

myclass init 2
after myclass!
after otherclass!
5
6
--end--
// 这里我没明白为什么会调用一次构造函数和两次析构函数,等下来补全说明
myclass delete
myclass delete