Part7 模板与泛型编程 Templates and Generic Programming(二)

  • Rule44: 将与参数无关的代码抽离templates
    Factor parameter-independent code out of templates
    使用Templates可能会导致代码膨胀,其二进制码带着重复或几乎重复的代码,数据或两者。其结果有可能源码看起来合身而整齐,但目标码却不是那么回事。所以需要知道如何避免这样的二进制浮夸。编写templates时,同样是将重复部分抽出来,但其中有个窍门。在非模板代码中,重复十分明确:你能够看到两个函数或两个classes之间的重复。然而在templates代码中,重复是隐晦的:毕竟只存在一份templates源码,所以你必须训练自己去感受当templates被具现化多次时可能发生的重复。
    如如下代码:
template<typename T,std::size_t n>
class SquareMatrix{
public:
    void invert();
};
//考虑如下代码:
SquareMatrix<double,5> sm1;
sm1.invert();
SquareMatrix<double,10> sm2;
sm2.invert();

这会具现化两份invert。这些函数并非完全相同,因为其中一个操作的是5*5矩阵,而另一个是10*10矩阵(n就是非类型模板参数)。但除了常量5和10,两个函数的其他部分完全相同。这是template引出代码膨胀的一个典型例子。
非类型模板参数(non-type template parameters)造成的代码膨胀,往往可以消除,做法是以函数参数或class成员变量替换template参数。

  • Rule45: 运用成员函数模板进行隐式模板类型转换
    指针支持隐式转换(implicit conversion), 在动态绑定中,派生类指针可以转换为基类指针.
    但是模板的实例化(instantiations)之间, 是单独存在的,没有明确的直接转换关系
    派生类的实例化的模板(SmartPtr), 不能转换为基类实例化的模板(SmartPtr);
    为了使用转换只能发生在可以转换的指针, 如”Derived->Base”, 不能逆序, 所以引入相关约束判断是否可以转换.
    在成员初始化列表(member initialization list)中调用get()函数, 判断是否可以隐式转换.
    使用成员函数模板的构造函数, 是成员函数的一种, 并不是重载复制构造函数, 所以类会自动生成一个默认构造函数.
#include <iostream>
using namespace std;

template<typename T>
class SmartPtr{
public:
    SmartPtr(){}//默认构造函数
    template<typename U> 
    SmartPtr(const SmartPtr<U> & other)
    {
        heldPtr = other.get();
        cout<<"SmartPtr::CopyConstructor"<<endl;
    }

    T* get() const
    {
        return heldPtr;
    }

private:
    T * heldPtr;

};

class Base{};

class Derived:public Base{};

int _tmain(int argc, _TCHAR* argv[])
{
    SmartPtr<Derived> spd;  
    SmartPtr<Base> spb(spd);  

    //SmartPtr<Base> spb1; 
    //SmartPtr<Derived> spd1(spb1); //无法进行隐身转换 

    SmartPtr<Base> spd2;  
    SmartPtr<Base> spd21(spd2); //使用默认的复制构造函数 
    getchar();
    return 0;
}

当出现 逆转换时,直接在编译阶段会报错。
注意:原始 成员函数模板的写法如下:

template<typename T>
class SmartPtr{
public:
 template<typename U>
 SmartPtr(const SmartPtr<U> &other);
}

以上代码的意思是: 对任何类型T和任何类型U,这里可以根据SmartPtr< U>生成一个SmartPtr< T>。因为 SmartPtr< T>有个构造函数接受一个SmartPtr< U>参数。但是这种simple model存在的问题就是没有约束性,可以正反进行转换,必须从某方面对这一member template所创建的成员函数群进行拣选或筛选。于是出现了上面的代码。再说一次,因为是编译时会具化代码,如果转换不符合关系,会直接报错。
还需要注意:成员函数模板与默认的构造函数不冲突,如果没有指明构造函数,会给出提示需要进行声明。

你可能感兴趣的:(Part7 模板与泛型编程 Templates and Generic Programming(二))