Effective C++读书笔记---模板与泛型编程

来源:互联网 发布:聚划算与淘宝的区别 编辑:程序博客网 时间:2024/05/22 01:58

C++ template机制身自是一部完整的图灵机(Turing-complete):它可以被用来计算任何可计算的值。于是导出了模板元编程(template metaprogramming),创建出“在C++编译器内执行并于编译完成时停止执行”的程序
四十一、条款41-了解隐式接口和编译器多态
1.class和template都支持接口(interfaces)和多态(polymorphism)
2.对classes而言接口是显式的(explicit),以函数签名为中心。多态则是通过virtual函数发生于运行期
3.对template参数而言,接口是隐式的(implicit),奠基于有效表达式。多态则是通过template具现化和函数重载解析(function overloading resolution)发生于编译期
四十二、了解typename的双重意义
1.template内出现的名称如果相依于某个template参数,称之为从属名称(dependent names)。如果从属性名称在class内呈嵌套状,我们称它为嵌套从属名称(nested dependent name)。不倚赖任何template参数的名称称为非从属名称(non-dependent names )
2.一般性规则很简单:任何时候当你想要在template中指涉一个嵌套从属类型名称,就必须在紧临它的前一个位置放上关键字typename。当然,“typename必须作为嵌套从属类型名称的前缀词”这一规则的例外是,typename不可以出现在base classes list内的嵌套从属类型名称之前,也不可在member initialization list(成员初值例)中作为base class修饰符。如:
template< typename T >
class Derived: public Base<T>::Nested                // base class list中
{                                // 不允许"typename"
public:
    explicit Derived( int x )
    : Base<T>::Nested(x)                    // mem. init. list中   
    {                            // 不允许"typename"
        typename Base<T>::Nested temp;            // 嵌套从属类型名称
        ...                    // 既不在base class list中也不在mem. init. list中,
    }                        // 作为一个base class修饰符需加上typename.
    ...
};
四十三、条款43-学习处理模板化基类内的名称
1.模板全特化时,class定义式最前头的“template<>”语法象征这既不是template也不是标准class,而是个特化版的template
2.在Derived class templates内调用Base class templates的函数,无法能过编译。因为编译器并不知道它继承什么样的class--更明确地说是没办法知道Base class templates是否有这个被Derived class templates调用的函数。这也是有原因的,因为编译器知道base class templates有可能被特化,而那个特化版本可能不提供和一般性template相同的接口。因此它往往拒绝在templatized base classes(模板化基类)内寻找继承而来的名称。
3.有三种办法可以令C++“不进入templatized base classes观察”的行为失效。
[1]在base class函数调用动作之前加上"this->"     // this->Fun();
[2]使用using声明式                 // using Bast<T>::Fun();
[3]明白指出被调用的函数位于base class内     // Base<T>::Fun();
第三种往往是最不让人满意的一个解法,因为如果被调用的是virtual函数,这种资格修饰(explicit qualification)会关闭“virtual绑定行为”
四十四、条款44-将与参数无关的代码抽离templates
1.templates生成多个classes和多个函数,所以任何template代码都不该与某个造成膨胀的template参数产生相依关系
2.因非类型模板参数(non-type template parameters)而造成的代码膨胀,往往可消除,做法是以函数参数或class成员变量替换template参数
3.因类型参数(type parameters)而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述(binary representations)的具现类型(instantiation types)共享实现码
四十五、运用成员函数模板接受所有兼容类型
1.所谓智能指针(smart pointers)是“行为像指针”的对象,并提供指针没有的机能。真实指针做得很好的一件事是,支持隐式转换(implicit conversions)。Derived class指针可以隐式转换为base class指针,“指向non-const对象”的指针可以转换为“指向const对象”……等等。下面是可能发生于三层继承体系的一些转换
class Top { ... };
class Middle:public Top { ... };
class Bottom:public Middle { ... };
Top* pt1 = new Middle;
Top* pt2 = new Bottom;
const Top* pct2 = pt1;     // 将Top*转换为const Top*
但如果用户想在自定的智能指针中模拟上述转换,会稍稍有点麻烦。我们希望以下代码通过编译:
template<typename T>
class SmartPtr
{
public:
    explicit SmartPtr( T* realPtr );
    ...
};

SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle);
SmartPtr<Top> pt2 = SmartPtr<Bottom>(new Bottom);
SmartPtr<const Top> pct2 = pt1;
但是,同一个template的不同具现体之间并不存在与生俱来的固有关系(注:这里意指如果以带有base-derived关系的B,D两类型分别具现化某个template,产生出来的两个具现体并不带有base-derived关系),所以编译器视SmartPtr<Middle>和SmartPtr<Top>为完全不同的classes
2.基于1的需求,我们需要为SmartPtr写一个构造模板。这样的模板是所谓member function templates(常简称为member templates),其作用是为class生成函数:
template< typename T >
class SmartPtr
{
public:
    template< typename U >                // member template,
    SmartPtr( const SmartPtr<U>& other );        // 为了生成copy构造函数
    ...
};
以上代码的意思是,对任何类型T和任何类型U,这里可以热气SmartPtr<U>生成一个SmartPtr<T>。这一类根据对象u创建对象t,而u和t的类型是同一个template的不同具现体,有时我们称之为泛化(generalized)copy构造函数。上面的泛化copy构造函数并未声明为explicit,是为了仿效原始指针类型之间的隐式转换,无需明白写出转型动作(cast)
3.要在“构造模板”实现代码中约束转换行为
template< typename T >
class SmartPtr
{
public:
    template<typename U>
    SmartPtr( const SmartPtr<U>& other )          // 以other的heldPtr
        : heldPtr( other.get() ) { ... }    // 初始化this的heldPtr
    T* get() const { return heldPtr; }
    ...
private:
    T* heldPtr;
                    // 这个SmartPtr持有的内置(原始)指针
};
4.如果你声明member templates用于“泛化copy构造”或“泛化assignment操作”,你还是需要声明正常的copy构造函数和copy assignment操作符
四十六、条款46-需要类型转换时请为模板定义非成员函数
1.当我们编写一个class template,而它所提供之“与此template相关的”函数支持“所有参数之隐式类型转换”时,请将那些函数定义为“class template内部的friend函数”
四十七、条款47-请使用traits class表现类型信息
1.Traits classes使得“类型相关信息”在编译器可用。它们以templates和"templates特化"完成实现
2.整合重载技术(overloading)后,traits classes有可能在编译器对类型执行if...else测试
四十八、条款48-认识template元编程
1.Template metaprogramming(TMP 模板元编程)是编写template-based C++程序并执行于编译期的过程。一旦TMP程序结束执行,其输出,也就是从templates具现出来的若干C++源码,便会一如往常地被编译
2.TMP可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率
3.TMP可被用来生成“基于政策选择组合”(based on combinations of plicy choices)的客户定制代码,也可用来避免生成对某些特殊类型并不适合的代码

原创粉丝点击