Effective C++ 7: Template & GP

    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; }
            }
            
        }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

相关阅读更多精彩内容

友情链接更多精彩内容