美文网首页
Effective C++ 7: Template & GP

Effective C++ 7: Template & GP

作者: my_passion | 来源:发表于2021-07-23 23:44 被阅读0次
        1   C++ template 机制的 发展
    
            [1] 建立 type-safe 的 容器
                
                    vector 等
    
            [2] GP code 与其所处理的对象 独立
                
                    algorithm: for_each / find 等
    
            [3] 是 图灵机
                
                    可用于计算 任何可计算的值
    
            [4] TMP
                
                    编译时计算
    

    1 implicit interface编译期 多态

        1   OO
                        相对于 `模板参数 T` 上的 `运算符重载` 而言 的 explicit, 而不是 相对于 编译期 implicit 生成的 explicit  
                            |\
                            |   含义 
                            |
                总是以 `explicit interface` + `运行期多态` 解决问题
                                |
                                |/
                        explicit public interface 
                        
                            = implicit public interface ( compiler 隐含生成 )
                                
                                + explicit 声明的 public interface
                                
                    void f(A& a)
                    {
                        if( a.size() > 0 && a != someNastyWidget )
                            /* ... */
                    }           
                
        2   GP
    
            与 OO 不同
                
                `implicit interface 和 编译期多态` 更重要
                        |
                        |   explicit interface 和 运行期多态 仍存在, 但 重要性 降低
                        |       
                        |   分析 
                        |/ 
                `从 function 到 function template 时 发生什么`
    
                    template <typename T>
                    void f(T& t)
                    {
                        if( t.size() > 0 && t != someNastyWidget )
                            /* ... */
                    }
    
            (1) `object 必须支持的 interface` 
                
                    由 template 中 `加诸于 object` 身上的 `操作` 决定
                                                           |
                                                           |/
                                            `implicict interface` 
                                                    |
                                                    |   即 
                                                    |/
                                    `模板参数 T 的 implicit interface 约束` 
                                    
                                        ————————————————————————————————————————————————————
                                        [1] 表面约束 |  不必满足
                                        ————————————————————————————————————————————————————
                                        [2] 真正约束 |  包含了 `运算符 重载` 带来的可能性                                 
                                        ————————————————————————————————————————————————————
                                        
                [1] 表面约束:   不必满足
                    
                    1]  T 必须 `提供 成员函数 size()`
                            
                            return 整数
    
                    2]  T 必须 `支持 operator!= 运算符重载`
                
                [2] 真正约束:   overloaded function 下
            
                    1]   T 必须 `支持 成员函数 size()` 
                        
                            但可 `从 base class 继承` 而来 
    
                    2]  size() 不必 return 整数
    
                            return 类型 X 
                                        |
                                        |/
                                        有 成员 比较运算符 operator> (Y, int)
    
                                            X 可转换为  Y
    
                    3]  T 不必支持 operator !=
    
                            operator!= (X, Y)
                            
                                T / someNastyWIdget 可 implicitly 转换为 X / Y
    
                        
                    Note
                        未考虑 逻辑与运算符重载 operator &&
    
            (2) 凡 `涉及 object` 的任何 `function call`
        
                    可能造成 `template 实例化` 以 使 函数调用 success
                                |   
                                |    
                                |/
                            编译期 `多态`    
                                    |
                                    |/
                                `不同 模板参数 T`
    
        3   compile-time / runtime polymorphism
    
            ————————————————————————————————————————————————————————
            编译期     哪个 overloaded function `该 (还没)` 被 `调用` 
            ————————————————————————————————————————————————————————    
            运行期     哪个 vf`                该         被 `绑定`
            ————————————————————————————————————————————————————————
            
        4   `explicit interface / implicit interface: 均在 compile-time 完成 检查`
    
            (1) 加诸于 `class`         身上的 explicit interface
    
            (2) 加诸于 `模板参数 T` 身上的    implicit interface
    
        5   remember
    
                OO vs. GP
    
                    都支持 interface 和 polymorphism
            
                    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
                                interface                           |   多态机制 
                    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
                    [1] class    |  explicit + function signature   |   vf -> 运行时多态  
                    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————  
                    [2] template |  implicit + 运算符重载            |   template 实例化 + 重载解析 ( overloading resolution ) -> 编译期多态 
                    ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————  
    

    2 typename 双重含义

        1 typename 双重含义 
        
            [1] `模板参数 声明式` 中, typename 
                                        |
                                        |
                                    等价 class
            
            
            [2] `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名 
                
                    的 一种方法 
    
        2   template 内可 `refer to` 2 种 名称`
                
                `依赖 / 非依赖 名称` 
    
            (1) 非依赖 名称
            
            (2) `依赖` 名称 -> `嵌套 依赖` 名称 -> `嵌套 依赖 类型` 名称
                
                ——————————————————————————————————————————————————————————————
                依赖  |   `依赖于 模板参数 T`        
                ——————————————————————————————————————————————————————————————
                嵌套  |   `作用域 限定符` 限定    // 如 `C::const_iterator`
                ——————————————————————————————————————————————————————————————
    
    
                `C++ template 解析`
    
                    compiler 默认 `嵌套依赖名称` 为 `non-type`
    
                        除非 `明确告诉 compiler` `嵌套依赖 名称` 是  `type` 名
                            ————————————————————————————————————————————————————————————————
                            [1] typename 
                            ————————————————————————————————————————————————————————————————
                            [2] 放 `base class list 或 mem init. list`
                            ————————————————————————————————————————————————————————————————
    
        3   typename 之 `别名`
    

    3 访问 模板基类名称

        1   需求
    
            编译期 `据 Info` 决定 `哪个 Info` pass 到 `哪家 Company ( 模板参数 T )`
            
                ————————————————————————————————————————
                    代码组织
                ————————————————————————————————————————
                [1] 1种 模板实参     
                [2] 模板基类
                [3] 模板派生类: public 继承 `模板基类` 
                
                    template<typename T>
                    void D<T>::sendExplicitMsg(const Info& info)
                    {
                        // send 前 log 
                        sendExplicit(info); // 欲 调 Base<T> 的 public interface func: sendExplicit(info)
                        // send 后 log
                    }
                ————————————————————————————————————————
                
        2   问题
    
            `C++ compiler 不进` 入 `模板化的 base class` 查找
            
                =>  遇 `模板派生类 D<T>` 定义 时  
    
                    compiler `无法知道 模板基类 B<T>` 的 `实例化版本` 长什么样
                        
                        => 无法知道 它 `有没有 其 主模板 的 interface func`
    
                            Note
                                
                                `全特化版 与 主模板 interface 可能不同` 
                                  |
                                  | 可能 
                                  |/
                                没有 主模板 中 某 `interface func`
    
        3   解决 
                        但不一定为真 
                          |\
                          |
            对 compiler `承诺 模板基类`
                
                `特化版 都支持 泛化版` 所提供的 `interface`
    
                    => compiler `未遇 interface 调用` 时, `先让 编译通过`
    
                        `遇 interface 调用` 
                        
                            + `相应 特化版(class) 不支持 interface`
                            
                                => `编译报错`
    
                                        
                                        D<T2> d; // B<T2> 内没 sendExplicitMsg(...)
                                        Info info;
                                        // ...
                                        d.sendExplicitMsg(info); // 编译 error
                
                
            3种方法
            ————————————————————————————————————————————————————————————————————————————————————————
            (1) this->                      |   this->sendExplicit(info);
            ————————————————————————————————————————————————————————————————————————————————————————        
            (2) using 声明                    |   using B<T>::sendExplicit    +   sendExplicit(info)
            ————————————————————————————————————————————————————————————————————————————————————————
            (3) Base class template 名限定 |   B<T>::sendExplicit(info);
            ————————————————————————————————————————————————————————————————————————————————————————    
    

    4 抽出 与 模板参数 T 无关code

        1   共性与变性分析
    
            (1) 2 个 function -> 共同部分 搬到 新 function -> 原 2 function 调 新 function
    
            (2) `2 个 class -> 共同部分 -> 新 class -> inheritance / composition`
    
            (3) `template 中, 重复 太隐晦`
    
                ————————————————————————————————————————————————
                重复 
                    
                    interface func `依赖于 2个模板参数 T+N`
                    
                        client 给定 2对 模板实参
                            
                            => 2 个 实例化版本 
                    
                                [1] Matrix<double, 3>::invert() 
                                [2] Matrix<double, 5>::invert()
                ————————————————————————————————————————————————
                    |
                    |   去重 
                    |/
                ————————————————————————————————————————————————————————————————
                    `继承 + 转调` 将 
                        
                        依赖于 `2个模板参数`
                            |
                            |   转换为
                            |/
                        只依赖一个 `模板参数 T` + 另一 `模板参数 N 替换为 para` 
                
                            令 interface func
                                template <typename T, std::size_t N> 
                                    void Derived::invert()  { this->invert(N); }
                                    
                                        转调 
                                            template <typename T>
                                                Base::invert(size_t n)
                ——————————————————————————————————————————————————————————————————
    
        2   `从某个角度看, 一些代码重复 反倒有利`
    
            (1) base 存 protected pointer 指向 数据
                
                    `封装性 降低`
    
            (2) base 存 ptr 指向 数据 -> 可能 动态或静态 内存分配
                
                    `ptr 该不该 delete ?`
    
        3   某些 mem func 操作 T* -> 调 另一 func 操作 void* -> 完成实际工作
    

    5 用 成员(函数)模板 接受 all 兼容 types

        1   `native pointer 与 smart pointer`
    
            `native pointer` 支持 `隐式转换`
    
                Derived* -> Base* 
                ptr to non-const-> ptrto const
    
                    SP: SP<Top> 与 SP<Mid> 是 完全不同的 class 
    
                        => SP 默认 `无隐式转换`
                                |
                                |   2   `SP 想 实现 隐式转换` 
                                |/
                    用 `成员 ( 函数 ) 模板` 
                
                如:  泛化 copy ctor: SP<U> -> SP<T>
            
                    蓄意 non-explicit => `让 SP 支持 隐式转换`
            
                    template<typename T>
                    class SP{
                    public:
                        template<typename U> // mem template 
                            SP(const SP<U>& rhs); 
                    };
                            |   `int* 到 doule* 的 隐式转换 被 编译器拒绝`
                            |           
                            |      也不希望 SP<int> 到 SP<sp> 的 隐式转换
                            |/
                            
                    3   SP `约束 转换`
    
                            [1] 思想 
                            
                                SP 的 internal ptr 能 隐式转换时, 才允许 SP 隐式转换  
                                
                            [2] 方法
                            
                                利用 rhs.get() 取出 internal ptr
                                    
                                    rhs 的 inernal ptr `初始化` lhs 的 inernal ptr `就是 限制` 
            
                                template<typename T>
                                    template<typename U> 
                                        SP::SP(const SP<U>& rhs)
                                            : ptr(rhs.get() ) { /* ... */ }
    
        4   mem template 用于 assignment
    
            shared_ptr copy/assignment 的 para 可为 
                ————————————————
                [1] shared_ptr
                [2] auto_ptr
                [3] weak_ptr
                ————————————————
    

    6 需 类型转换 时, 在 template 内定义 非成员函数: friend 函数(模板)

        part4-7 的 泛化
    
        1   `类 / 非成员函数 -> 泛化`
    
            [1] `模板(函数) 实参推导` 可能失败                  template<typename T>
                                                                const Rational<T> 
                    整型 -> 类类型 // 2 -> Rational<T>          operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
                    |                                               return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator() );
                    |   解决                                    }
                    |                                           
                    |                                           Rational<int> oneHalf(1, 2);
                    |/                                          Rational<int> result = oneHalf * 2; // 编译 error
            [2] 非模板 
                    
                    2 -> Rational 可 隐式转换
            
        2   解决
                            friend 作用 `不是 访问` class 的 `non-public 部分`
                                |\
                                |   这里
                                |
            `模板类` 内 `定义 friend 函数(模板)`
    
                模板类 `实例化` 的同时
                    
                    friend 函数(模板) 被 `自动 实例化` 为 函数
                                        |
                                        |   `整型 作 实参 调 类的 Ctor`
                                        |/
                                    整型 到 类类型 的 隐式转换 // 2 -> Rational<T>
    
            (1) 模板类 `内 声明` friend
                    
                    模板类 外定义 friend
                        
                        `链接失败`
    
            (2) 解决1:    模板类 `内 定义` friend           
    
            (3) 解决2
                
                为 支持 `inline`
                    
                    令 `模板类 内 friend 函数(模板)` 定义式
                        
                        调 `模板类 外 helper 函数模板`
                                                |
                                                |   若必要
                                                |/
                                            头文件内 定义 helper template
    
        3   `模板类 内 模板名` 可作 `模板名 + 模板参数` 的 `简化式`
                    |
                    |/
                Rational == Rational<T>
    

    7 用 traits class 表现 type infomation

        1   5种 迭代器
                
                [1] 空 struct: 只起 tag 作用 
            
                [2] `除 输出迭代器 外`, 从 `输入迭代器` 开始, `逐层 继承`
            
            ——————————————————————————————————————————
            InputIter
                只读
                    istream_iterator
            ——————————————————————————————————————————
            OutputIter
                只写
                    ostream_iterator
            ——————————————————————————————————————————
            ForwardIter
                读写
                    单向链表 slist: 非标准
            ——————————————————————————————————————————
            BiIter
                双向
                    list set map multiset multimap
            ——————————————————————————————————————————
            RAIter
                随机
                    vector deque string
            ——————————————————————————————————————————
    
        2   advance 表现
        
                移动 迭代器
    
                template<typename Iter, typename D>
                    void advance(Iter& iter, D d);
    
                        观念上 只是做 iter += d
    
                            实际要用 traits
    
        3   traits class
    
                习惯上 总是实现为 struct
            
            (1) traits 是 `1 种技术`
                    
                    用于 `萃取 type` 的 `某种信息`
                                |           |
                                |/          |/
                            iterator    category
                            
                            
            (2) traits 要 `同时支持 built-in / user-defined 类型` 
                    
                    泛化 / 特化 template
    
            (3) traits `设计`
                    
                [1] 确定 对 目标 type
                    
                    `要 萃取 什么信息`
    
                [2] 为 `次信息` 选 `nane`
                        |           |   
                        |           |
                        |/          |/
                    category    iterator_category
                        
                [3] `template 泛化 + 特化 版`
    
                    template<typename Iter>
                    struct iterator_traits
                    {
                        typedef typename 
                            Iter::iterator_category iterator_category;
                    };
    
                    template<typename Iter>
                    struct iterator_traits<Iter*> // 偏特化: 针对 native pointer
                    {
                        typedef 
                            random_access_iterator_tag iterator_category;
                    };
    
            (4) `用户自定义 iterator 类型`, 必须 `内嵌 次信息 的 别名`
                                                        |
                                                        |/
                                                    iterator_category                                           
    
            (5) 实现 advance
            
                思路
    
                    `traits` 引发 `编译期` 发生于 type 身上的 `条件计算/判断`
    
                        => 不能用 if-else 语句 + typeid, 因为
    
                            `if 语句 运行期 才执行`
    
                实现
    
                    [1] `重载 function ( template ) 组`
                            
                            差异只在于 `traits 参数`
                        
                    [2]  `traits class 所 `萃取 信息` 的 `临时对象` 作 实参 `调 重载 function`
                                                                |
                                                                |/
                                                            `只用于 实参推导` 之 `类型匹配`
                                                                            |
                        compiler `重载解析` 调 适当 `重载版本`                 |   => 不需要 name
                                                |                           |
                                                |/                          |
                                            随机/双向/输入                    |
                                                                            |
                template<typename Iter, typename D>                         |
                void advance(Iter& iter, D d)                               |
                {                                                           |
                    doAdvance(iter, d,                                      |
                              typename                                      |/
                                std::iterator_traits<Iter>::iterator_category() 
                             );
                } 
                
                template<typename Iter, typename D>
                void doAdvance(Iter& iter, D d,
                               std::random_access_iterator_tag) 
                {
                    iter += d;
                }
    

    8 TMP 模板元编程

        1   TMP
    
            (1) `编译期 计算`-> 输出: `template 实例化 code`
                
                    `再` 正常 `编译`
    
            (2) 利弊
                
                ——————————————————————————————————————————————
                利   
                    ——————————————————————————————————————————
                    [1] `错误检测` 从 运行期 `提前` 到 编译期 
                    ——————————————————————————————————————————
                    [2] 高效
                            ——————————————————————————————————
                            1] 可执行文件 小 
                            2] 运行期    短 
                            3] 内存     小 
                ——————————————————————————————————————————————
                弊
                    编译时间变长
                ——————————————————————————————————————————————
                
        2   traits 解法是1种 TMP
    
        3   advance 的 if...else + typeid 解法` 的 `编译期问题`       
            
                    随机迭代器 版本
                        |\
                        |
                `不使用的版本`, compiler 也会 `生成 code` 
                                                |
                                                |/
                                            却 `无法保证 编译通过` 
                                                
                                                虽然是 运行期执行 
    
    === 详细 
    

    1 implicit interface编译期 多态

    2 typename 双重含义

        1 typename 双重含义 
        
            [1] `模板参数 声明式` 中, typename 
                                        |
                                        |
                                    等价 class
            
            
            [2] `明确告诉 compiler` `嵌套依赖 名称` 是 `type` 名 
                
                    的 一种方法 
    
        2   template 内可 `refer to` 2 种 名称`
                
                `依赖 / 非依赖 名称` 
    
            (1) 非依赖 名称
            
            (2) `依赖` 名称 -> `嵌套 依赖` 名称 -> `嵌套 依赖 类型` 名称
                
                ——————————————————————————————————————————————————————————————
                依赖  |   `依赖于 模板参数 T`        
                ——————————————————————————————————————————————————————————————
                嵌套  |   `作用域 限定符` 限定    // 如 `C::const_iterator`
                ——————————————————————————————————————————————————————————————
    
    
                `C++ template 解析`
    
                    compiler 默认 `嵌套依赖名称` 为 `non-type`
    
                        除非 `明确告诉 compiler` `嵌套依赖 名称` 是  `type` 名
                            ————————————————————————————————————————————————————————————————
                            [1] typename 
                            ————————————————————————————————————————————————————————————————
                            [2] 放 `base class list 或 mem init. list`
                            ————————————————————————————————————————————————————————————————
            
    
                [1] 
                    // error
                    template<typename C>
                    void f(const C& container,          // C                    非 嵌套 name
                           C::const_iterator* iter);    // C::const_iterator       嵌套 name
                           
                    // ok
                    template<typename C>
                    void f(const C& container, 
                           typename C::const_iterator* iter); 
    
                [2]
                    template<typename T>
                    class Derived: public Base<T>::Nested  // 1] base class list 中 不允许 typename
                    {
                    public:
                        explicit Derived(int x)
                            : Base<T>::Nested(x)           // 2] mem init. list  中 不允许 typename
                        {
                            typename Base<T>::Nested temp; // else: 需 typename
                        }
                    };
    
        3   typename 之 `别名`
            
                std:iterator_traits<Iter>::value_type 是 Iter 所指对象的 type
    
                    Iter 是 std::list<string>::iterator => value_type 是 string
            
                template<typename Iter>
                void f(Iter iter)
                {
                    typedef typename std:iterator_traits<Iter>::value_type value_type;
                    value_type temp(*iter);
                }
    

    3 访问 模板基类名称

        1   需求
    
            编译期 `据 Info` 决定 `哪个 Info` pass 到 `哪家 Company ( 模板参数 T )`
    
                // [1] 1种 模板实参 
                class T1
                {
                public:
                    void send(const std::string& msg);
                };
                
                // [2] 模板基类
                template<typename T>
                class B
                {
                public:
                    void sendExplicit(const Info& info) // class Info { /* ... */ };
                    {
                        std::string msg;
                        // 据 info -> msg
                        T t;
                        t.send(msg);
                    }
                };
    
                // [3] 模板派生类: public 继承 `模板基类` 
                template<typename T>
                class D: public B<T>
                {
                public:
                    void sendExplicitMsg(const Info& info)
                    {
                        // send 前 log 
                        sendExplicit(info); // 欲 调 Base<T> 的 public interface func: sendExplicit(info)
                        // send 后 log
                    }
                    // ...
                };  
                    
        2   问题
    
            `C++ compiler 不进` 入 `模板化的 base class` 查找
            
                =>  遇 `模板派生类 D<T>` 定义 时  
    
                    compiler `无法知道 模板基类 B<T>` 的 `实例化版本` 长什么样
                        
                        => 无法知道 它 `有没有 其 主模板 的 interface func`
    
                            Note
                                
                                `全特化版 与 主模板 interface 可能不同` 
                                  |
                                  | 可能 
                                  |/
                                没有 主模板 中 某 `interface func`
    
                                    template<> 
                                    class B<T2>
                                    {
                                    public:
                                        // 无 sendExplicit() 
                                    };
    
        3   解决 
                        但不一定为真 
                          |\
                          |
            对 compiler `承诺 模板基类`
                
                `特化版 都支持 泛化版` 所提供的 `interface`
    
                    => compiler `未遇 interface 调用` 时, `先让 编译通过`
    
                        `遇 interface 调用` 
                        
                            + `相应 特化版(class) 不支持 interface`
                            
                                => `编译报错`
    
                                        
                                        D<T2> d; // B<T2> 内没 sendExplicitMsg(...)
                                        Info info;
                                        // ...
                                        d.sendExplicitMsg(info); // 编译 error
                
                
            3种方法
            ————————————————————————————————————————————————————————————————————————————————————————
            (1) this->                      |   this->sendExplicit(info);
            ————————————————————————————————————————————————————————————————————————————————————————        
            (2) using 声明                    |   using B<T>::sendExplicit    +   sendExplicit(info)
            ————————————————————————————————————————————————————————————————————————————————————————
            (3) Base class template 名限定 |   B<T>::sendExplicit(info);
            ————————————————————————————————————————————————————————————————————————————————————————    
    

    4 抽出 与 模板参数 T 无关code

        class template 的 mem func `使用时 才 实例化`
    
        1   共性与变性分析
    
            (1) 2 个 function -> 共同部分 搬到 新 function -> 原 2 function 调 新 function
    
            (2) `2 个 class -> 共同部分 -> 新 class -> inheritance / composition`
    
            (3) `template 中, 重复 太隐晦`
    
                ————————————————————————————————————————————————
                重复 
                    
                    interface func `依赖于 2个模板参数 T+N`
                    
                        client 给定 2对 模板实参
                            
                            => 2 个 实例化版本 
                    
                                [1] Matrix<double, 3>::invert() 
                                [2] Matrix<double, 5>::invert()
                ————————————————————————————————————————————————
                    |
                    |   去重 
                    |/
                ————————————————————————————————————————————————————————————————
                    `继承 + 转调` 将 
                        
                        依赖于 `2个模板参数`
                            |
                            |   转换为
                            |/
                        只依赖一个 `模板参数 T` + 另一 `模板参数 N 替换为 para` 
                
                            令 interface func
                                template <typename T, std::size_t N> 
                                    void Derived::invert()  { this->invert(N); }
                                    
                                        转调 
                                            template <typename T>
                                                Base::invert(size_t n)
                ——————————————————————————————————————————————————————————————————
                
                template <typename T, std::size_t N> 
                class Matrix
                {
                public:
                    void invert();  // 求逆
                };
    
                Matrix<double, 3> m1;
                // ...
                m1.invert(); 
    
                Matrix<double, 5> m2;
                // ...
                m2.invert(); 
                
                    |
                    |   去重
                    |/
                template <typename T>
                class MatrixBase
                {
                protected:
                    MatrixBase(std::size_t n, T* p)
                        : size(n), ptr(p) {}
                        
                    void invert(std::size_t n);
                private:
                    std::size_t size;
                    T* ptr;
                };
    
                template <typename    T, 
                          std::size_t N> 
                class Matrix
                {
                public:
                    Matrix()
                        : MatrixBase<T>(N, data) {}
    
                    void invert()
                    {
                        this->invert(N);         // [3] 告诉 compiler Base 的 所有版本 都支持 public func invert(...)
                    }   
                private:
                    T data[N*N];                 // [2] 也可以 动态内存分配
                    
                    using MatrixBase<T>::invert; // [1] 避免 hide base 的 mem func
                };  
    
        2   `从某个角度看, 一些代码重复 反倒有利`
    
            (1) base 存 protected pointer 指向 数据
                
                    `封装性 降低`
    
            (2) base 存 ptr 指向 数据 -> 可能 动态或静态 内存分配
                
                    如何判断 `ptr 是否该 delete ?`
    
        3   某些 mem func 操作 T* -> 调 另一 func 操作 void* -> 完成实际工作
    

    5 用 成员(函数)模板 接受 all 兼容 types

        1   `native pointer 与 smart pointer`
    
            `native pointer` 支持 `隐式转换`
    
                Derived* -> Base* 
                ptr to non-const-> ptrto const
    
                    SP: SP<Top> 与 SP<Mid> 是 完全不同的 class 
    
                        => SP 默认 `无隐式转换`
                                |
                                |   2   `SP 想 实现 隐式转换` 
                                |/
                    用 `成员 ( 函数 ) 模板` 
                
                如:  泛化 copy ctor: SP<U> -> SP<T>
            
                    蓄意 non-explicit => `让 SP 支持 隐式转换`
            
                    template<typename T>
                    class SP{
                    public:
                        template<typename U> // mem template 
                            SP(const SP<U>& rhs); 
                    };
                            |   `int* 到 doule* 的 隐式转换 被 编译器拒绝`
                            |           
                            |      也不希望 SP<int> 到 SP<sp> 的 隐式转换
                            |/
                            
                    3   SP `约束 转换`
    
                            [1] 思想 
                            
                                SP 的 internal ptr 能 隐式转换时, 才允许 SP 隐式转换  
                                
                            [2] 方法
                            
                                利用 rhs.get() 取出 internal ptr
                                    
                                    rhs 的 inernal ptr `初始化` lhs 的 inernal ptr `就是 限制` 
            
                                template<typename T>
                                    template<typename U> 
                                        SP::SP(const SP<U>& rhs)
                                            : ptr(rhs.get() ) { /* ... */ }
                    
    
                                template<typename T>
                                class SP
                                {
                                public:
                                    template<typename U> 
                                    SP(const SP<U>& rhs)
                                        : ptr(rhs.get() ) { /* ... */ }
                                        
                                    T* get() const { return ptr; }
                                private:
                                    T* ptr;
                                };
    
        4   mem template 用于 assignment
    
            shared_ptr copy/assignment 的 para 可为 
                ————————————————
                [1] shared_ptr
                [2] auto_ptr
                [3] weak_ptr
                ————————————————
    
            template<typename T>
            class shared_ptr
            {
            public:
                template<typename U> 
                explicit shared_ptr(U* p);
                    
                // [1] copy ctor
                shared_ptr(shared_ptr const& sp); 
                
                template<typename U> // 泛化 copy ctor: 支持 隐式转换
                shared_ptr(shared_ptr<U> const& sp); 
                
                template<typename U> 
                explicit shared_ptr(weak_ptr<U> const& sp);
                
                template<typename U> 
                explicit shared_ptr(auto_ptr<U> const& sp);
                
                // [2] assignment
                shared_ptr& 
                operator=(shared_ptr const& sp); // assignment
                
                template<typename U> // 泛化 asignment
                shared_ptr& 
                operator=(shared_ptr<U> const& sp);
                
                template<typename U> 
                shared_ptr& 
                operator=(auto_ptr<U> const& sp);
            };
    

    6 需 类型转换 时, 在 template 内定义 非成员函数: friend 函数(模板)

        part4-7 的 泛化
    
        1   `类 / 非成员函数 -> 泛化`
    
            [1] `模板(函数) 实参推导` 可能失败 
                
                    整型 -> 类类型 // 2 -> Rational<T>
                    |
                    |   解决
                    |/
            [2] 非模板 
                    
                    2 -> Rational 可 隐式转换
            
                template<typename T>
                class Rational
                {
                public:
                    Rational (const T& numerator = 0, const T& denominator = 1);
                    const T& numerator() const;
                    const T& denominator() const;
                };
    
                template<typename T>
                const Rational<T> 
                operator*(const Rational<T>& lhs, const Rational<T>& rhs) {
                    return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator() );
                }
                
                Rational<int> oneHalf(1, 2);
                Rational<int> result = oneHalf * 2; // 编译 error
    
        2   解决
                            friend 作用 `不是 访问` class 的 `non-public 部分`
                                |\
                                |   这里
                                |
            `模板类` 内 `定义 friend 函数(模板)`
    
                模板类 `实例化` 的同时
                    
                    friend 函数(模板) 被 `自动 实例化` 为 函数
                                        |
                                        |   `整型 作 实参 调 类的 Ctor`
                                        |/
                                    整型 到 类类型 的 隐式转换 // 2 -> Rational<T>
    
            (1) 模板类 `内 声明` friend
                    
                    模板类 外定义 friend
                        
                        `链接失败`
    
                template<typename T>
                class Rational
                {
                friend  // [1] 声明
                    const Rational operator*(const Rational& lhs, const Rational& rhs);       
                public:
                    /* 同前 */
                };
                
                // [2] 定义 
                template<typename T>
                const Rational<T> 
                Rational::operator*(const Rational<T>& lhs, const Rational<T>& rhs) { /* 同前 */ }
    
            (2) 解决1:    模板类 `内 定义` friend           
    
                template<typename T>
                class Rational
                {
                friend           // class template 内 定义 friend function template
                    const Rational 
                    operator*(const Rational& lhs,
                              const Rational& rhs)
                    {
                        // ...
                    }
                              
                public:
                    // ... // 同前    
                };
            
            (3) 解决2
                
                为 支持 `inline`
                    
                    令 `模板类 内 friend 函数(模板)` 定义式
                        
                        调 `模板类 外 helper 函数模板`
                                                |
                                                |   若必要
                                                |/
                                            头文件内 定义 helper template
    
                    template<typename T>
                    class Rational;
                    
                    // [2] 
                    template<typename T>
                    const Rational<T> 
                    doMultiply(const Rational<T>& lhs, const Rational<T>& rhs);
                    
                    template<typename T>
                    class Rational
                    {
                    friend     // [1] 令 `模板类 内 friend 函数(模板)` 调 `模板类 外 helper 函数模板` 
                        const Rational 
                        operator*(const Rational& lhs, const Rational& rhs) {
                            return doMultiply(lhs, rhs);
                        }         
                    public:
                        // ...   
                    };
    
                    // [3] 若必要, 头文件内 定义 helper template
                    template<typename T>
                    const Rational<T> 
                    doMultiply(const Rational<T>& lhs,
                               const Rational<T>& rhs)
                    {
                        return Rational<T>(lhs.numerator() * rhs.numerator(),
                                           lhs.denominator() * rhs.denominator() );
                    }
    
                Note
                    就本例而言, 这种方法意义不大, 但对 复杂函数,却意义很大
    
        3   `模板类 内 模板名` 可作 `模板名 + 模板参数` 的 `简化式`
                    |
                    |/
                Rational == Rational<T>
    
            template<typename T>
            class Rational
            {
            friend         
                const Rational<T> 
                operator*(const Rational<T>& lhs, const Rational<T>& rhs);
            public:
                /* 同前 */
            };
            
            <=>
    
            template<typename T>
            class Rational
            {
            friend           // 声明
                const Rational 
                operator*(const Rational& lhs, const Rational& rhs);          
            public:
                /* 同前 */
            };
    

    7 用 traits class 表现 type infomation

        1   5种 迭代器
    
            Input iterator
                只读
                istream_iterator
    
            Output iterator
                只写
                ostream_iterator
    
            forward iterator
                读写
                非 STL 的 程序库中 单向链表 slist
    
            Bidirectional iterator
                双向
                list set map multiset multimap
    
            random access iterator
                随机
                vector deque string
    
            // tag struct
    
            struct 
            input_iterator_tag {};
    
            struct 
            output_iterator_tag {};
    
            struct 
            forward_iterator_tag: public input_iterator_tag {};
    
            struct 
            bidirectional_iterator_tag: public forward_iterator_tag {};
    
            struct 
            random_access_iterator_tag: public bidirectional_iterator_tag {};
    
        2   advance 表现
        
                移动 迭代器
    
                template<typename Iter, typename D>
                    void advance(Iter& iter, D d);
    
                        观念上 只是做 iter += d
    
                            实际要用 traits
    
        3   traits class
    
                习惯上 总是实现为 struct
            
            (1) traits 是 `1 种技术`
                    
                    用于 `萃取 type` 的 `某种信息`
                                |           |
                                |/          |/
                            iterator    category
                            
                            
            (2) traits 要 `同时支持 built-in / user-defined 类型` 
                    
                    泛化 / 特化 template
    
            (3) traits `设计`
                    
                [1] 确定 对 目标 type
                    
                    `要 萃取 什么信息`
    
                [2] 为 `次信息` 选 `nane`
                        |           |   
                        |           |
                        |/          |/
                    category    iterator_category
                        
                [3] `template 泛化 + 特化 版`
    
                    template<typename Iter>
                    struct iterator_traits
                    {
                        typedef typename 
                            Iter::iterator_category iterator_category;
                    };
    
                    template<typename Iter>
                    struct iterator_traits<Iter*> // 偏特化: 针对 native pointer
                    {
                        typedef 
                            random_access_iterator_tag iterator_category;
                    };
    
            (4) `用户自定义 iterator 类型`, 必须 `内嵌 次信息 的 别名`
                                                        |
                                                        |/
                                                    iterator_category
                                                    
                template<...>
                class list
                {
                public:
                    class iterator
                    {
                    public:
                        typedef 
                            bidirectional_iterator_tag iterator_category;
                    };
                };
    
            (5) 实现 advance
            
                思路
    
                    `traits` 引发 `编译期` 发生于 type 身上的 `条件计算/判断`
    
                        => 不能用 if-else 语句 + typeid, 因为
    
                            `if 语句 运行期 才执行`
    
                实现
    
                    [1] `重载 function ( template ) 组`
                            
                            差异只在于 `traits 参数`
                        
                    [2]  `traits class 所 `萃取 信息` 的 `临时对象` 作 参数 `调 重载 function`
                                                                |
                                                                |/
                                                            `只用于 实参推导` 之 `类型匹配`
                                                                            |
                        compiler `重载解析` 调 适当 `重载版本`                 |  
                                                |                           |
                                                |/                          |
                                            随机/双向/输入                    |
                                                                            |
                template<typename Iter, typename D>                         |
                void advance(Iter& iter, D d)                               |
                {                                                           |
                    doAdvance(iter, d,                                      |
                              typename                                      |/
                                std::iterator_traits<Iter>::iterator_category() 
                             );
                } 
                
                template<typename Iter, typename D>
                void doAdvance(Iter& iter, D d,
                               std::random_access_iterator_tag) // 第 3 para 不需要 name
                {
                    iter += d;
                }
    
                template<typename Iter, typename D>
                void doAdvance(Iter& iter, D d,
                               std::bidirectional_iterator_tag ) 
                {
                    if( d > 0)
                    {
                        while (d--)
                            ++iter;
                    }
                    else
                    {
                        while (d++)
                            --iter;
                    }
                }
    
                template<typename Iter, typename D>
                void doAdvance(Iter& iter, D d,
                               std::input_iterator_tag ) 
                {
                    if( d < 0)
                        throw std::out_of_range(" - distance ");
                    while(d--)
                            ++iter;
                }
    

    8 TMP 模板元编程

        1   TMP
    
            (1) `编译期 计算`-> 输出: `template 实例化 code`
                
                    `再` 正常 `编译`
    
            (2) 利弊
                
                ——————————————————————————————————————————————
                利   
                    ——————————————————————————————————————————
                    [1] `错误检测` 从 运行期 `提前` 到 编译期 
                    ——————————————————————————————————————————
                    [2] 高效
                            ——————————————————————————————————
                            1] 可执行文件 小 
                            2] 运行期    短 
                            3] 内存     小 
                ——————————————————————————————————————————————
                弊
                    编译时间变长
                ——————————————————————————————————————————————
                
        2   traits 解法是1种 TMP
    
        3   advance 的 if...else + typeid 解法` 的 `编译期问题`       
            
                    随机迭代器 版本
                        |\
                        |
                `不使用的版本`, compiler 也会 `生成 code` 
                                                |
                                                |/
                                            却 `无法保证 编译通过` 
                                                
                                                虽然是 运行期执行 
    
            template<typename Iter, typename D>
            void advance(Iter& iter, D d)
            {
                if( typeid( typename std::iterator_traits<Iter>::iterator_category ) 
                    == typeid( std::random_access_iterator_tag )  )
                {
                    iter += d;
                }
                else
                {
                    else
                    {
                        if( d > 0) { while (d--) ++iter; }
                        else { while (d++) --iter; }
                    }
                }
                
            }
    
            std::list<int>::iterator iter;
            // ...
            advance(iter, 10);
    
            // 实例化版本
            void advance(std::list<int>::iterator& iter, int d)
            {
                if( typeid( std::iterator_traits< std::list<int>::iterator >::iterator_category ) 
                    == typeid( std::random_access_iterator_tag )  )
                {
                    iter += d; // 编译不过
                }
                else
                {
                    if( d > 0) { while (d--) ++iter; }
                    else { while (d++) --iter; }
                }
                
            }
    

    相关文章

      网友评论

          本文标题:Effective C++ 7: Template & GP

          本文链接:https://www.haomeiwen.com/subject/wswsmltx.html