美文网首页
C++ Primer-chapter16 模板 与 泛型编程

C++ Primer-chapter16 模板 与 泛型编程

作者: my_passion | 来源:发表于2021-04-22 09:55 被阅读0次

1 模板


    (1) 类/函数 模板 区别 
        
        否/是有  `模板实参推断`
            
            使用时 是/否必须 `explicitly 指定 模板实参`
            
                Queue<int> queue;
                compare(1, 0); // 不用 compare<int>(1, 0)

    (2) 模板形参

        1]  类型形参 
        
        2]  非类型形参
        
            template <typename T, size_t N> 

                #include <iostream>

                template <typename T, size_t N>
                void array_init( T (&parm) [N] ) 
                {   //(1) func template 的 `para 是 数组的引用
                    for( size_t i = 0; i < N; ++i)
                        parm[i] = i;
                }

                int main()
                {
                    int arr[5];
                    //(2) 函数调用 时, compiler `从 数组实参 计算 非类型形参 的值`
                    //    instantiate array_init( int (&) [5] )
                    array_init(arr); 
                }

2 实例化

    模板实参推导

        (1) `受限转换`

            1) const 转换

                1) func template 的 para 是 `non-reference type` 时, 
                para/arg type 都

                `const ignored`

            2) `array / function type` 转换为 `pointer`


            3) template para 的 type 被 推导出 后, 
                
                `不再 implicitly converted`

3 template 编译模型

    (1) inclusion 编译模型 

        [1] 头文件 要 #include 4 种 定义

            1] func template 
            
            2] class template 的
                    
                    1>  非模板  mem func 
                    
                    2>  模板 mem func
                     
            3] class 的 
                
                    模板 mem func    

        [2] 问题: 多 源文件 use 同一 template 时, 其 `同一实例 可能 实例化多次`

            compiler 是否优化, 要查 compiler 用户指南

                // 1. utilities.h
                template <class T>
                int compare(const T&, const T&);
                #include "utilities.cpp" 

                // 2. utilities.cpp
                template <typename T>
                int compare(const T& x, const T& y)
                {
                    if (x < y)
                        return -1;
                    if (y < x)
                        return 1;
                    return 0;
                }

        [3] separate 编译模型: `不通用`

4 类模板成员

    [1] class template scope 内, 
        
        用 class name 时, 可 不用指定 template para

    [2] 类模板 外 定义 mem func 时

        必须
        1) 以 template 开头, 后接 template para list
        2) class name 包含 template para

            template <class T>
            return_type Queue<T>::member_name

    [3] class template 的 mem 非模板函数 是 template

        与 非成员 的 模板函数 区别

            1} 实例化 时, `不进行 模板实参 推导` 
                
                => 允许 arg 的 type conversion 
                
                `template para 由 定义 class template 的 obj 的 template arg 确定`

            2] `更灵活`

                // void push(const T& val)
                // => 2) instantiates Queue<int>::push(const int&)
                // => 3) short 型 arg s converted to int 型 and passed to push
                short s = 1;
                q1.push(s); 

    [4] 成员模板

        用途 
            
            泛化 copy ctor / assignment 
                
                Queue<short> -> Queue<int>
                
        mem template  类外定义 时, 
        
            `必须含 2个 template para list`

                template <class T> template <class Iter>
                void Queue<T>::assign(Iter beg, Iter end) { /* ... */ }

    [5] template para 一 一 映射: (有时才有意义) 
        
        QueueItem<T> 的 友元 唯一对应  Queue<T>, 

            template <class T>
            class QueueItem
            {
                friend class Queue<T>;  
                //...
            }

5 泛型 句柄类

将 `RC` 和 继承层次中 `基础 obj 的 ptr 管理` 泛型化
image.png
image.png
    将 `concrete Handle 拆成 2 层
        
        generic Handle class
        
        余下 `中介层 class ( 如 名为 ) Handle_client`


    dtor 调用链

    `~Handle_client() -> 调 ~Handle()-> 调 deRC(): *RC 减完后 == 0 时, delete ptr -> 调 ptr 所指 实际类型 的 dtor`


    // === 1
    template <class T>
    class Handle
    {
    private:
        T* ptr;          
        size_t* pRC;

        void deRC()
        {
            if (-- * pRC == 0)
            {
                delete ptr;
                delete pRC;
            }
        }
    public:
        Handle(T* p = 0) :
            ptr(p), pRC(new size_t(1)) {}

        Handle(const Handle& rhs) :
            ptr(rhs.ptr), pRC(rhs.pRC) { ++* pRC; }
        Handle& operator=(const Handle&);
        ~Handle() { deRC(); }

        T& operator*();
        T* operator->();
        const T& operator*() const;
        const T* operator->() const;
    };

    template <class T>
    inline Handle<T>&
    Handle<T>::operator=(const Handle& rhs)
    {
        ++* rhs.pRC;
        deRC();

        ptr = rhs.ptr;
        pRC = rhs.pRC;

        return *this;
    }

    template <class T>
    inline T&
    Handle<T>::operator*()
    {
        if (ptr)
            return *ptr;
        throw std::runtime_error("dereference of unbound Handle");
    }
    template <class T>
    inline const T&
    Handle<T>::operator*() const
    {
        if (ptr)
            return *ptr;
        throw std::runtime_error("...");
    }

    template <class T>
    inline T*
    Handle<T>::operator->()
    {
        if (ptr)
            return ptr;
        throw std::runtime_error("access through unbound Handle");
    }

    template <class T>
    inline const T*
    Handle<T>::operator->() const
    {
        if (ptr)
            return ptr;
        throw std::runtime_error("...");
    }

    // === 2
    class Handle_client
    {
    private:
        Handle<Base> handle;
    public:
        Handle_client() : handle() {}

        Handle_client(const Base& rB):
            handle(rB.clone()) {}

        // Handle_client(const Handle_client& rhs) { handle = rhs.handle; }
        // Handle_client& operator=(const Handle_client& rhs) { handle = rhs.handle; return *this;}
        // ~Handle_client() { handle.~Handle(); }
        
        //(4) * ->: forward (转发) work to Handle class
        const Base& operator*() const { return *handle; }
        const Base* operator->() const { return handle.operator->(); }
    };


    void test()
    {
        Base b = Base("book1", 20);
        Derived d = Derived("book2", 30);

        Handle_client hc1(b);
        Handle_client hc2(d);
        {
            Handle_client hc3 = hc1;
            Handle_client hc4 = hc2;
        }

        hc1 = hc2;
    }

after `Handle_client hc4 = hc2` result:
image.png image.png

6 防止 自身赋值

    assignment 为什么要 防止 `自身赋值`?
                                |
                                |/
                    若 `释放 旧资源`  => 引发问题
                                            |
                                            |
                                        因 赋给新值 时, 要 use 旧资源 

        例: String 的 internal ptr + 赋值运算中 不检查自我赋值, 直接 delete [] p; 
        
                class String {
                public:             
                  String& operator=(const String& rhs);
                private:
                  char *p; // new str[];
                };

                String& String::operator=(const String& rhs)
                {
                    // not check self assignmemt
                    
                    //1) delete old memory
                    delete [] p;    
                    
                    //2) allocate new memory
                    p = new char[strlen(rhs.p) + 1];
                    
                    //3) copy resource pointed to by rhs's pointer mem
                    strcpy(p, rhs.p);
                    
                    return *this;  
                }

7 模板 特化 / specialization

    (1) 意义
    
        对某些类型 
    
            泛化版
                1] `错误`

                2]  实例化 `效率低`

                // 泛化版  对 T = const char* 错误
                template <typename T>
                int compare(const T& v1, const T& v2)
                {
                    if (v1 < v2)
                        return -1;
                    if (v2 < v1)
                        return 1;
                    return 0
                }   

    (2) function template 特化

        形式
            [1] template 后接 空尖括号 <>
            [2] template name 后 <> 中 指定 特化版 template paras

        T = const char* 时,
            const T& (const reference) +   const char* (指向 const 的 ptr) = const char* const&

            // eg2. solution of eg1
            template <>
            int 
            compare<const char*>(const char* const& v1, 
                                 const char* const& v2)
            {
                return strcmp(v1, v2);
            }

    (3) class template 特化?有几种,各有什么区别

        default, copy C 风格 字符串 只会 copy ptr
        
            若 `ptr 指向 动态内存, 往往需要 特化版`

        [1] 全特化 + 外部 定义 mem 时` -> `不用 template<>

                // 泛化
                template <class T>
                class Queue
                {
                public:
                    void push(const T&);
                };

                template <>
                class Queue<const char*>
                {
                public:
                    void push(const char*);
                };

                void Queue<const char*>::push(const char* p_val)
                {
                    return real_queue.push(p_val);
                }

        [2] 只特化 class template 的 `部分 mem` -> 用 template<>


            template <>
            void Queue<const char*>::push(const char* const& p_val)
            {
                char* p_new = new char[ strlen(p_val) + 1 ];
                strncpy(p_new, p_val, strlen(p_val) + 1 );

                QueueItem<const char*>* pt =
                    new QueueItem<const char*>(p_new);

                if (empty())
                    head = tail = pt;
                else
                {
                    tail->tail = pt;
                    tail = pt;
                }
            }

            template <>
            void Queue<const char*>::pop()
            {
                QueueItem<const char*>* pt = head;
                delete head->item;

                head = head->next;
                delete pt;
            }

        [3] 只 特化 class template 的 部分 template para: 偏特化

            template <class T1, class T2>
            class A
            {
            };

            // partial specialization: fix T2 as int
            template<class T1>
            class A<class T1, int>
            {
            };

相关文章

网友评论

      本文标题:C++ Primer-chapter16 模板 与 泛型编程

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