C++学习13:模板的类型和特化

前言:C++学习8:模板初步理解

1 模板的类型

1.1 Class template,类模板

设计类时,类中定义的类型暂时不指定。在之前的学习中有谈过,见模板入门

template<typename T>
class complex
{
public:
    complex(T r = 0, T i = 0)
    : re(r), im(i)
    {}
    complex& operator += (const complex&);
    T real () const { return re; }
    T imag () const { return im; }
private:
    T re, im;

    friend complex& __doapl (complex*, const complex&);
};

{
    complex<double> c1(2.5, 1.5);
    complex<int> c2(2, 6);
    ...
}

1.2 Function template,函数模板

设计一个函数时,函数的形参和返回类型暂时不指定,要进行关键步骤:实参推导。在之前的学习中有谈过,见模板入门

template <class T>
inline const T& min(const T& a, const T& b)
{
    return b < a ? b : a;
}

class stone
{
public:
    stone(int w, int h, int we) 
    : _w(w), _h(h), _weight(we)
    { }
    bool operator< (const stone& rhs) const
    { return _weight < rhs._weight; }
private:
    int _w, _h, _weight;
};

1.3 Member template,成员模板

语法:下面的程序中template ,这个小模板在大模板template 中,就被称为成员模板。
用途:可以想象外面的大模板是变化的东西,而在T1和T2确定之后,里面的小模板又可以变化,变化的类型是U1和U2。
作用:常用于构造函数,让构造函数可以构造的更灵活。

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;

    T1 first;
    T2 second;

    pair()
        : first(T1()), second(T2()) {}
    pair(const T1& a, const T2& b)
        : first(a), second(b) {}
        
    template <class U1, class U2>//成员模板,把U1构造为T1,U2构造为T2。故U1必须属于T1,U2必须属于T2
    pair(const pair<U1, U2>& p)
        : first(p.first), second(p.second) {}
};

对其进行使用,类比如下:

class Base1{};					//假设Base1为“鱼类”
class Derived1:public Base1{};	//假设Derived1为“鲫鱼”

class Base2{};					//假设Base2为“鸟类”
class Derived2:public Base2{};	//假设Derived2为“麻雀”

//	   T1		  T2
pair<Derived1, Derived2>p;	//制造一个p,把鲫鱼和麻雀放为一对
pair<Base1, Base2>p2(p);	//制造一个p2,把鱼类和鸟类放为一对

//由上面一行的内容:可以构造出如下语句
//	  T1	 T2				U1			U2
pair<Base1, Base2>p2(pair<Derived1, Derived2>());

由上例:鲫鱼和麻雀可以放入鱼类和鸟类中,而鱼类和鸟类不能放入鲫鱼和麻雀。(子类属于父类而父类不属于子类,即up-cast:向上层转换)
例,智能指针shared_ptr:

template<typename _Tp>
class shared_ptr:public __shared_ptr<_Tp>
{
...
    template<typename _Tp1>
    explicit shared_ptr(_Tpl* __p)
    :__shared_ptr<_Tp>(__p){}
...    
};

Base1* ptr = new Derived1;				//向上层(父类)转换,是可以的,合理的(如指向鱼的指针指向鲫鱼,鲫鱼是鱼,故可以)
shared_ptr<Base1>sptr(new Derived1);	//模拟up-cast

2 specialization,模板特化

2.1 泛化与特化

泛化即full specialization。特化的反义词是泛化。泛化是模板的特征,表示一个类型,用的时候再指定就行。
而特化针对某些独特的类型要特殊设计,就是把模板中的一个或几个类型给固定了下来。
形式:template<>,尖括号里面没有东西。
例子:

//泛化:
template <class Key>
struct hash{ };

//特化:
template<>
struct hash<char>
{
    size_t operator() (char x) const { return x; }
};

template<>
struct hash<int>
{
    size_t operator() (int x) const { return x; }
};

template<>
struct hash<long>
{
    size_t operator() (long x) const { return x; }
};

使用就很简单了:

cout << hash() (1000);

2.2 patial specialization,模板局部特化(偏特化)

2.2.1 个数的偏

泛化类型:

template<typename T, typename Alloc=...>
class vector
{
    ...
};

为了一种特殊的设计,将T绑定成了bool类型,可以偏这一个,对应定义一种特殊的设计。

template<typename Alloc=...>
class vector<bool, Alloc>
{
    ...

2.2.2 范围的偏

泛化类型:

template <typename T>
class C
{
    ...
};

若想只对指针类型进行特化处理,当使用者使用的类型只能是指针时,则应该调用下面这种特化版本。

template <typename U>
class C<U*>//只对指针类型进行特化处理
{
    ...
};

C<string> obj1;		//使用的是上面那种泛化类型
C<string*> obj2;	//使用的是当前这种特化类型

3 template template parameter,模板模板参数

template<typename T, 
        template <typename T>	//模板模板参数:本身是个模板参数,而这个参数又是模板
            class Container		//接上,模板模板参数:本身是个模板参数,而这个参数又是模板
        >
class XCls
{
private:
    Container<T> c;//拿第一个模板参数做参数
public:
    ......
};
template<typename T>
using Lst = list<T, allocator<T>>;

//    T  
XCls<string, list> mylst1;//想传入一个链表,让链表的元素作为string。但错误,模板有第二参数。
XCls<string, Lst> mylst2;//正确

另例:

template<typename T,
            template <typename T>	//模板模板参数
                class SmartPtr		//模板模板参数
        >
class XCls
{
private:
    SmartPtr<T> sp;
public:
    XCls():sp(new T) { }
};

XCls<string, shared_ptr> p1;
XCls<string, unique_ptr> p2;//错误,原因,独自的特性
XCls<int, weak_ptr> p3;//错误,原因,独自的特性
XCls<long, auto_ptr> p4;

反例:第二模板参数不是模板了,绑定已被确定:

template <class T, class Sequence = deque<T>>
class stack
{
    friend bool operator== <> (const stack&, const stack&);
    friend bool operator< <> (const stack&, const stack&);

protected:
    Sequence c;//底层容器
......
};

stack<int> s1;
stack<int, list<int>> s2;

你可能感兴趣的:(侯捷老师C++)