zoukankan      html  css  js  c++  java
  • cppPrimer学习16th

    cppPrimer学习16th

    TODO

    16.22
    16.23
    

    16.1

    给出实例化的定义
    我们在调用模块的时候,传递确定的参数,编译器为我们构造真实的函数或者对象
    

    16.2

    // 16.2 编写你自己的compare版本
    
    #include <iostream>
    
    template <typename T>
    int compare(const T &a, const T &b)
    {
        if (a > b)
            return 1;
        if (a < b)
            return -1;
        return 0;
    }
    
    int main(int argc, char const *argv[])
    {
        std::cout << compare(1, 2) << std::endl;
        while (1)
            ;
        return 0;
    }
    

    16.3

    提示未定义 operator<
    error: no match for 'operator>' (operand types are 'const Sales_data' and 'const Sales_data')
    
    // 16.2 编写你自己的compare版本
    
    #include <iostream>
    
    class Sales_data
    {
    private:
        int a;
    
    public:
        Sales_data() : a(0) {}
        ~Sales_data() {}
    };
    
    template <typename T>
    int compare(const T &a, const T &b)
    {
        if (a > b)
            return 1;
        if (a < b)
            return -1;
        return 0;
    }
    
    int main(int argc, char const *argv[])
    {
        Sales_data a;
        Sales_data b;
        std::cout << compare(1, 2) << std::endl;
        std::cout << compare(a, b) << std::endl;
        while (1)
            ;
        return 0;
    }
    

    16.4

    // 16.4 编写行为类似标准库find算法的模版.函数需要两个模版类型参数,一个表示函数的迭代器参数,另一个表示值的类型.
    //      使你的函数在一个vector<int> 和 list<string>中查找给定值
    
    #include <vector>
    #include <list>
    #include <string>
    #include <iostream>
    
    template <typename it_type, typename value_type>
    it_type find(const it_type begin, const it_type end, const value_type val)
    {
        for (auto it = begin; it != end; it++)
        {
            if (*it == val)
                return it;
        }
        return end;
    }
    
    template <typename it_type, typename value_type>
    std::ostream &PrintFind(const it_type &begin, const it_type &end, const value_type &val, std::ostream &o = std::cout)
    {
        it_type find_it = find(begin, end, val);
        if (find_it == end)
            return o << "Null to find";
        else
            return o << *find_it;
    }
    
    int main(int argc, char const *argv[])
    {
        std::vector<int> vs({1, 2, 3, 4, 5, 6, 7, 8, 9});
    
        std::cout << *find(vs.begin(), vs.end(), 2) << std::endl;
        PrintFind(vs.begin(), vs.end(), 2) << std::endl;
        PrintFind(vs.begin(), vs.end(), 10) << std::endl;
    
        std::list<std::string> ls({"123", "456", "ABC"});
        PrintFind(ls.begin(), ls.end(), "999") << std::endl;
    
        while (1)
            ;
        return 0;
    }
    
    

    16.5

    // 16.5 编写一个printf 支持任意大小任意元素类型的数组
    
    #include <iostream>
    #include <string>
    template <typename elem_type, int size>
    void print(elem_type (&arr)[size])
    {
        for (auto ch : arr)
        {
            std::cout << ch << std::endl;
        }
    }
    int main(int argc, char const *argv[])
    {
        std::string as[] = {"123", "456", "789"};
        int ai[] = {1, 2, 3, 4, 5, 6};
        print(as);
        print(ai);
        while (1)
            ;
        return 0;
    }
    
    

    16.6

    //16.6 	你认为一个接受数组实参的标准库函数 begin 和end是如何工作的,定义你自己版本的begin和end
    // 		也就是定义 begin(array)和end(array)
    #include <iostream>
    #include <string>
    template <typename elem_type, size_t size>
    elem_type *Begin(elem_type (&array)[size])
    {
        return array;
    }
    
    template <typename elem_type, size_t size>
    elem_type *End(elem_type (&array)[size])
    {
        return array + size;
    }
    
    int main(int argc, char const *argv[])
    {
        std::string as[] = {"123", "456", "789"};
    
        for (auto i = Begin(as); i != End(as); i++)
            std::cout << *i << std::endl;
    
        while (1)
            ;
        return 0;
    }
    

    16.7

    //16.7	编写一个 constexpr 模版,返回给定参数的大小
    template <typename T, unsigned N>
    constexpr unsigned SizeOfArray(const T (&arr)[N])
    {
        return N;
    }
    

    16.8

    //16.8 在97页非关键概念中,c++程序在for喜欢用!= 替换 <  的原因是什么
    迭代器一般定义了 != 和= 但是不一定定义了<
    

    16.9

    // 16.9 什么是函数模版? 什么是类模版?
    函数有参数是模版,编译器自动推断模版参数
    类模版,有参数是模版,需要手动定义模版参数的
    

    16.10

    //16.10 当一个类模版被实例化,会发生什么?
    1. 生成类的非模版函数
    2. 生成需要使用的类的模版函数
    

    16.11

    // 16.11 修正以下程序
    template <typename elemType> class ListItem;
    template <typename elemType> class List {
    public:
      List<elemType>();
      List<elemType>(const List<elemType> &);
      List<elemType>& operator=(const List<elemType> &);
      ~List();
      void insert(ListItem *ptr, elemType value);
    private:
      ListItem *front, *end;
    };
    
    // 修改注释部分
    template <typename elemType> class ListItem;
    template <typename elemType> class List {
    public:
      List<elemType>();
      List<elemType>(const List<elemType> &);
      List<elemType>& operator=(const List<elemType> &);
      ~List();
      //void insert(ListItem *ptr, elemType value);
      void insert(ListItem<elemType> *ptr, elemType value);
    private:
      //ListItem *front, *end;
      ListItem<elemType> *front, *end;
    };
    

    16.12

    // 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员
    
    #include <vector>
    #include <memory>
    #include <string>
    #include <iostream>
    #include <initializer_list>
    #include <exception>
    #include <algorithm>
    
    template <typename T>
    class BlobPtr;
    template <typename T>
    class Blob;
    template <typename T>
    class ConstBlobPtr;
    
    template <typename T>
    bool operator==(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator!=(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator<(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator>(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator<=(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator>=(const Blob<T> &a, const Blob<T> &b);
    
    template <typename T>
    class Blob
    {
        friend BlobPtr<T>;
        friend ConstBlobPtr<T>;
    
        friend bool operator==<T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator!=<T>(const Blob<T> &a, const Blob<T> &b);
        // clang-format off
        friend bool operator< <T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator> <T>(const Blob<T> &a, const Blob<T> &b);
        // clang-format on
        friend bool operator<=<T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator>=<T>(const Blob<T> &a, const Blob<T> &b);
    
        // 以下两个应该是为了外部方便获取类型
        typedef T value_type;
        typedef typename std::vector<T>::size_type size_type;
    
    private:
        std::shared_ptr<std::vector<T>> data;
        void check(size_type i, const std::string &msg) const;
    
    public:
        Blob() : data(std::make_shared<std::vector<T>>()) {}
    
        Blob(const Blob<T> &s) : data(std::make_shared<std::vector<T>>(*s.data)) {}
        Blob(Blob<T> &&a) noexcept : data(std::move(a.data)) {}
    
        Blob &operator=(const Blob<T> &s);
        Blob &operator=(Blob<T> &&) noexcept;
    
        Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {}
        size_type size() const { return data->size(); }
        bool empty() const { return data->empty(); }
    
        void push_back(T &val) { data->push_back(val); };
        void push_back(const T &val) { data->push_back(std::move(val)); }
        void pop_back();
    
        T &back();
        const T &back() const;
        T &front();
        const T &front() const;
    
        T &operator[](size_type i);
        const T &operator[](size_type i) const;
    
        BlobPtr<T> begin();
        BlobPtr<T> end();
    
        ConstBlobPtr<T> cbegin() const;
        ConstBlobPtr<T> cend() const;
    
        void print(std::ostream &o);
    };
    
    template <typename T>
    Blob<T> &Blob<T>::operator=(const Blob<T> &s)
    {
        data = std::make_shared<std::vector<T>>(*s.data);
        return *this;
    }
    
    template <typename T>
    Blob<T> &Blob<T>::operator=(Blob<T> &&s) noexcept
    {
        if (this != s)
        {
            data = std::move(s.data);
            s.data = nullptr;
        }
        return *this;
    }
    
    template <typename T>
    void Blob<T>::print(std::ostream &o)
    {
        for (auto ch : (*data))
            o << ch << ",";
        o << std::endl;
    }
    
    template <typename T>
    void Blob<T>::check(size_type i, const std::string &msg) const
    {
        if (i >= size())
        {
            throw std::out_of_range(msg);
        }
    }
    
    template <typename T>
    void Blob<T>::pop_back()
    {
        check(0, "empty to pop_back");
        data->pop_back();
    }
    
    template <typename T>
    T &Blob<T>::back()
    {
        check(0, "Get empty Back()");
        return data->back();
    }
    template <typename T>
    const T &Blob<T>::back() const
    {
        check(0, "Get empty Back()");
        return data->back();
    }
    
    template <typename T>
    T &Blob<T>::front()
    {
        check(0, "Get empty front()");
        return data->front();
    }
    template <typename T>
    const T &Blob<T>::front() const
    {
        check(0, "Get empty front()");
        return data->front();
    }
    
    template <typename T>
    T &Blob<T>::operator[](size_type i)
    {
        check(i, "Get [" + std::to_string(i) + "]");
        return data->at(i);
    }
    
    template <typename T>
    const T &Blob<T>::operator[](size_type i) const
    {
        check(i, "Get [" + std::to_string(i) + "]");
        return data->at(i);
    }
    
    template <typename T>
    BlobPtr<T> Blob<T>::begin()
    {
        return BlobPtr<T>(*this);
    }
    template <typename T>
    BlobPtr<T> Blob<T>::end()
    {
        return BlobPtr<T>(*this, size());
    }
    
    template <typename T>
    ConstBlobPtr<T> Blob<T>::cbegin() const
    {
        return ConstBlobPtr<T>(*this);
    }
    template <typename T>
    ConstBlobPtr<T> Blob<T>::cend() const
    {
        return ConstBlobPtr<T>(*this, size());
    }
    
    //****************************************************************************
    template <typename T>
    bool operator==(const Blob<T> &a, const Blob<T> &b)
    {
        return (*a.data == *b.data);
    }
    template <typename T>
    bool operator!=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(a == b);
    }
    
    template <typename T>
    bool operator<(const Blob<T> &a, const Blob<T> &b)
    {
        return std::lexicographical_compare(a.data->begin(), a.data->end(), b.data->begin(), b.data->end());
    }
    
    template <typename T>
    bool operator>(const Blob<T> &a, const Blob<T> &b)
    {
        return (b < a);
    }
    template <typename T>
    bool operator<=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(b > a);
    }
    template <typename T>
    bool operator>=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(a < b);
    }
    
    //****************************************************************************
    // 定义 Blob::iterator
    
    template <typename T>
    bool operator==(const BlobPtr<T> &, const BlobPtr<T> &);
    template <typename T>
    bool operator!=(const BlobPtr<T> &, const BlobPtr<T> &);
    template <typename T>
    bool operator<(const BlobPtr<T> &, const BlobPtr<T> &);
    template <typename T>
    bool operator>(const BlobPtr<T> &, const BlobPtr<T> &);
    template <typename T>
    bool operator<=(const BlobPtr<T> &, const BlobPtr<T> &);
    template <typename T>
    bool operator>=(const BlobPtr<T> &, const BlobPtr<T> &);
    
    template <typename T>
    class BlobPtr
    {
    private:
        std::weak_ptr<std::vector<T>> wptr;
        std::size_t curr;
        std::shared_ptr<std::vector<T>> check(size_t i, const std::string &msg) const;
    
    public:
        friend bool operator==<T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        friend bool operator!=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        // clang-format off
        friend bool operator< <T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        friend bool operator> <T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        friend bool operator<=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        friend bool operator>=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b);
        // clang-format on
    
        BlobPtr() : curr(0) {}
        BlobPtr(const Blob<T> &pt, size_t at = 0) : wptr(pt.data), curr(at) {}
        T &operator*()
        {
            return check(curr, "Get elem[] out of range")->at(curr);
        }
        T &operator[](size_t at)
        {
            return check(at, "Get elem[] out of range")->at(at);
        }
        const T &operator*() const
        {
            return check(curr, "Get elem[] out of range")->at(curr);
        }
        const T &operator[](size_t at) const
        {
            return check(at, "Get elem[] out of range")->at(at);
        }
        const T *operator->() const
        {
            return &this->operator*();
        }
        T *operator->()
        {
            return &this->operator*();
        }
        BlobPtr operator++();
        BlobPtr operator++(int);
        BlobPtr operator--();
        BlobPtr operator--(int);
        BlobPtr &operator+=(size_t);
        BlobPtr &operator-=(size_t);
        BlobPtr operator+(size_t) const;
        BlobPtr operator-(size_t) const;
    };
    
    template <typename T>
    std::shared_ptr<std::vector<T>> BlobPtr<T>::check(size_t i, const std::string &msg) const
    {
        auto spt = wptr.lock();
        if (spt)
        { // 使用之前必须复制到 shared_ptr
            if (i >= spt->size())
                throw std::out_of_range(msg);
        }
        else
        {
            throw std::runtime_error("unbound Blob<T>Ptr");
        }
        return spt;
    }
    
    // 前置++,先++,再返回
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator++()
    {
        check(curr, "++");
        curr++;
        return *this;
    }
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator++(int)
    {
        auto ret = *this;
        ++*this;
        return *this;
    }
    // 前置++,先++,再返回
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator--()
    {
        check(curr, "--");
        curr--;
        return *this;
    }
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator--(int)
    {
        auto ret = *this;
        --*this;
        return *this;
    }
    
    template <typename T>
    BlobPtr<T> &BlobPtr<T>::operator+=(size_t off)
    {
        curr += off;
        check(curr, "increment past end of Blob<T>Ptr");
        return *this;
    }
    template <typename T>
    BlobPtr<T> &BlobPtr<T>::operator-=(size_t off)
    {
        curr -= off;
        check(curr, "increment past end of Blob<T>Ptr");
        return *this;
    }
    
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator+(size_t off) const
    {
        BlobPtr<T> ret = *this;
        ret += off;
        return ret;
    }
    
    template <typename T>
    BlobPtr<T> BlobPtr<T>::operator-(size_t off) const
    {
        BlobPtr<T> ret = *this;
        ret -= off;
        return ret;
    }
    
    //***********            friend           *******************************//
    template <typename T>
    bool operator==(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return (a.curr == b.curr);
    }
    template <typename T>
    bool operator!=(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return !(a == b);
    }
    
    template <typename T>
    bool operator<(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return (a.curr < b.curr);
    }
    template <typename T>
    bool operator>(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return (b < a);
    }
    template <typename T>
    bool operator<=(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return !(a > b);
    }
    template <typename T>
    bool operator>=(const BlobPtr<T> &a, const BlobPtr<T> &b)
    {
        return !(a < b);
    }
    
    // template <typename T>
    // std::ostream &operator<<(std::ostream &o, const T &Blob_val)
    // {
    
    // }
    
    //****************************************************************************
    // 定义 Blob::iterator
    
    template <typename T>
    bool operator==(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    template <typename T>
    bool operator!=(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    template <typename T>
    bool operator<(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    template <typename T>
    bool operator>(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    template <typename T>
    bool operator<=(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    template <typename T>
    bool operator>=(const ConstBlobPtr<T> &, const ConstBlobPtr<T> &);
    
    template <typename T>
    class ConstBlobPtr
    {
    private:
        std::weak_ptr<std::vector<T>> wptr;
        std::size_t curr;
        std::shared_ptr<std::vector<T>> check(size_t i, const std::string &msg) const;
    
    public:
        friend bool operator==<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        friend bool operator!=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        // clang-format off
        friend bool operator< <T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        friend bool operator> <T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        friend bool operator<=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        friend bool operator>=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b);
        // clang-format on
    
        ConstBlobPtr() : curr(0) {}
        ConstBlobPtr(const Blob<T> &pt, size_t at = 0) : wptr(pt.data), curr(at) {}
        const T &operator*() const
        {
            return check(curr, "Get elem[] out of range")->at(curr);
        }
        const T &operator[](size_t at) const
        {
            return check(at, "Get elem[] out of range")->at(at);
        }
        const T *operator->() const
        {
            return &this->operator*();
        }
        ConstBlobPtr operator++();
        ConstBlobPtr operator++(int);
        ConstBlobPtr operator--();
        ConstBlobPtr operator--(int);
        ConstBlobPtr &operator+=(size_t);
        ConstBlobPtr &operator-=(size_t);
        ConstBlobPtr operator+(size_t) const;
        ConstBlobPtr operator-(size_t) const;
    };
    
    template <typename T>
    std::shared_ptr<std::vector<T>> ConstBlobPtr<T>::check(size_t i, const std::string &msg) const
    {
        auto spt = wptr.lock();
        if (spt)
        { // 使用之前必须复制到 shared_ptr
            if (i >= spt->size())
                throw std::out_of_range(msg);
        }
        else
        {
            throw std::runtime_error("unbound Blob<T>Ptr");
        }
        return spt;
    }
    
    // 前置++,先++,再返回
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator++()
    {
        check(curr, "++");
        curr++;
        return *this;
    }
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator++(int)
    {
        auto ret = *this;
        ++*this;
        return *this;
    }
    // 前置++,先++,再返回
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator--()
    {
        check(curr, "--");
        curr--;
        return *this;
    }
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator--(int)
    {
        auto ret = *this;
        --*this;
        return *this;
    }
    
    template <typename T>
    ConstBlobPtr<T> &ConstBlobPtr<T>::operator+=(size_t off)
    {
        curr += off;
        check(curr, "increment past end of Blob<T>Ptr");
        return *this;
    }
    template <typename T>
    ConstBlobPtr<T> &ConstBlobPtr<T>::operator-=(size_t off)
    {
        curr -= off;
        check(curr, "increment past end of Blob<T>Ptr");
        return *this;
    }
    
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator+(size_t off) const
    {
        ConstBlobPtr<T> ret = *this;
        ret += off;
        return ret;
    }
    
    template <typename T>
    ConstBlobPtr<T> ConstBlobPtr<T>::operator-(size_t off) const
    {
        ConstBlobPtr<T> ret = *this;
        ret -= off;
        return ret;
    }
    
    //***********            friend           *******************************//
    template <typename T>
    bool operator==(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return (a.curr == b.curr);
    }
    template <typename T>
    bool operator!=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return !(a == b);
    }
    
    template <typename T>
    bool operator<(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return (a.curr < b.curr);
    }
    template <typename T>
    bool operator>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return (b < a);
    }
    template <typename T>
    bool operator<=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return !(a > b);
    }
    template <typename T>
    bool operator>=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b)
    {
        return !(a < b);
    }
    
    int main(int argc, char const *argv[])
    {
        try
        {
            std::string hello = "hello";
            Blob<std::string> blob_s({"1"});
            blob_s.pop_back();
            // 触发check 异常
            //blob_s.pop_back();
            blob_s.push_back("2");
            blob_s.push_back(hello);
            //
            std::cout << blob_s.size() << std::endl;
            blob_s.print(std::cout);
            std::cout << blob_s.back() << std::endl;
            std::cout << blob_s[blob_s.size() - 1] << std::endl;
    
            // 测试 iterator
            BlobPtr<std::string> blob_pt1(blob_s);
            std::cout << blob_pt1[1] << std::endl;
    
            // 测试迭代器
            std::cout << "By iterator" << std::endl;
            for (auto b = blob_s.begin(); b != blob_s.end(); b++)
            {
                std::cout << *b << std::endl;
            }
        }
        catch (const std::exception &msg)
        {
            std::cout << msg.what() << std::endl;
        }
    
        {
            Blob<std::string> sb1{"a", "b", "c"};
            Blob<std::string> sb2 = sb1;
    
            sb2[2] = "b";
    
            if (sb1 > sb2)
            {
                for (auto iter = sb2.cbegin(); iter != sb2.cend(); ++iter)
                    std::cout << *iter << " ";
                std::cout << std::endl;
            }
    
            ConstBlobPtr<std::string> iter(sb2);
            std::cout << iter->size() << std::endl;
        }
    
        while (1)
            ;
        return 0;
    }
    
    

    16.13

    // 16.3 解释你为BlobPtr的相等和关系运算符选择那种类型的友好关系
    
    模版参数T 一直的 重载都为其友元关系
    

    16.14

    16.15

    // 16.14 编写Screen类模版,用非类型参数定义Screen的高和宽,可以当宏使用
    #include <string>
    #include <algorithm>
    #include <iostream>
    
    //using pos = int;
    using pos = std::string::size_type;
    
    template <pos, pos>
    class Screen;
    
    template <pos H, pos W>
    std::istream &operator>>(std::istream &, Screen<H, W> &);
    
    template <pos H, pos W>
    std::ostream &operator<<(std::ostream &, const Screen<H, W> &);
    
    template <pos H, pos W>
    class Screen
    {
    
        friend std::istream &operator>><H, W>(std::istream &, Screen<H, W> &);
        friend std::ostream &operator<<<H, W>(std::ostream &, const Screen<H, W> &);
    
    private:
        pos curr = 0;
        std::string contents;
    
    public:
        Screen() = default;
        Screen(char c) : contents(H * W, c) {}
        char get() const { return contents[curr]; }
        char get(pos a, pos b) const { return contents[a * W + b]; }
        Screen &set(char c)
        {
            contents[curr++] = c;
            curr = std::min(curr, H * W);
            return *this;
        }
        Screen &set(pos a, pos b, char c)
        {
            contents[a * W + b] = c;
            return *this;
        }
        Screen &move(pos a, pos b);
    };
    
    template <pos H, pos W>
    Screen<H, W> &Screen<H, W>::move(pos a, pos b)
    {
        curr = a * W + b;
        return *this;
    }
    
    template <pos H, pos W>
    std::istream &operator>>(std::istream &is, Screen<H, W> &s)
    {
        std::string input;
        is >> input;
        for (char ch : input)
            s.set(ch);
        return is;
    }
    template <pos H, pos W>
    std::ostream &operator<<(std::ostream &os, const Screen<H, W> &s)
    {
        for (pos r = 0; r != H; ++r)
        {
            for (pos c = 0; c != W; ++c)
            {
                os << s.get(r, c);
            }
            os << std::endl;
        }
        return os;
    }
    
    int main()
    {
        Screen<5, 5> screen('x');
        screen.set(2, 2, 'o');
        std::cout << screen << std::endl;
    
        std::cout << "please input some characters as you like:";
        std::cin >> screen;
        std::cout << screen << std::endl;
        while (1)
            ;
        {
            /* code */
        }
    }
    
    // xxxxx
    // xxxxx
    // xxoxx
    // xxxxx
    // xxxxx
    
    // please input some characters as you like:1234512345123451234512345999
    // 12345
    // 12345
    // 12345
    // 12345
    // 12345
    

    16.17

    在定义模板参数类型的时候,typename 和class 没什么不同
    在 有些时候需要使用 模板类的类型的时候,需要加上typename,因为默认识别为类的成员 p593
    
    T::x a;  T是模板,有两种理解
    1. x是静态成员,与a相*------默认是这个
    2. 定义一个a变量,类型是T::x
    
    
    

    16.18

    // 解释下面的代码是否合法
    > (a) template <typename T, U, typename V> void f1(T, U, V);
    > (b) template <typename T> T f2(int &T);
    > (c) inline template <typename T> T foo(T, unsigned int*);
    > (d) template <typename T> f4(T, T);
    > (e) typedef char Ctype;
    > template <typename Ctype> Ctype f5(Ctype a);
    
    a. template <typename T, typename U, typename V> void f1(T, U, V);
    b. template <typename T> T f2(int &a);	// typename 被隐藏
    c. template <typename T> inline T foo(T, unsigned int*); //inline的位置
    d. template <typename T> void f4(T, T); // 提供返回类型
    e. 隐藏了typedef
        
    
    

    16.19

    16.20

    // 16.19 接受容器的引用,打印容器的元素.使用 size_type 和size 控制打印
    // 16.20 使用迭代器
    #include <iostream>
    #include <vector>
    #include <list>
    #include <string>
    using namespace std;
    
    template <typename T>
    printv(const T &v)
    {
        for (typename T::size_type i = 0; i < v.size(); i++)
            cout << v.at(i) << "<>";
        cout << endl;
    }
    
    template <typename T>
    printv2(const T &v)
    {
        for (auto c = v.begin(); c != v.end(); c++)
            cout << *c << "<>";
        cout << endl;
    }
    
    int main(int argc, char const *argv[])
    {
        vector<int> v1({1, 2, 3, 4, 5, 6, 7});
        printv(v1);
    
        //因为printv使用的是 size 不是迭代器,所以不能用list
        list<string> v2({"123", "456"});
        printv2(v2);
    
        while (1)
            ;
        return 0;
    }
    
    

    16.21

    // 16.21 实现自己的DebugDelete版本
    #include <iostream>
    #include <memory>
    
    using namespace std;
    
    class DebugDelete
    {
    private:
        std::ostream &dbgos;
    
    public:
        DebugDelete(std::ostream &o = std::cout) : dbgos(o) {}
        template <typename T>
        void operator()(T *elem) const
        {
            dbgos << "delete by DebugDelete" << std::endl;
            delete elem;
        }
    };
    
    int main(int argc, const char **argv)
    {
        DebugDelete d;
        int *a = new int;
        d(a);
    
        int *b = new int;
        DebugDelete()(b);
    
        {
    
            std::unique_ptr<int, DebugDelete> ui(new int, DebugDelete());
            // ui.release(); 释放ui但保留内存
            // ui.reset();   释放ui内存的东西,会调用DebugDelete
            std::cout << "/* message */" << std::endl;
        }
        while (1)
            ;
        return 0;
    }
    

    16.24

    // 16.24 为你的Blob添加一个构造函数支持两个迭代器
    
    // 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员
    
    // 16.24
    template <typename type_it>
    Blob(type_it a, type_it b) : data(std::make_shared<std::vector<T>>(a, b)) {}
    
    try
    {
        std::list<std::string> ls({"A1", "A2", "A3"});
        Blob<std::string> blob_s(ls.begin(), ls.end());
        blob_s.print(std::cout);
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << '
    ';
    }
    

    16.25

    // 16.25 解释下面的语句
    
    // 显式实例化,需要在其他的地方定义
    extern template class vector<string>;
    // 定义
    template class vector<Sales_data>;
    

    16.26

    // 16.26 假设Nodefault 是一个没有默认构造函数的类,我们可以显式实例化 vecctor<NoDefault> 吗?
    
    不能,因为vector需要调用默认的构造函数
    

    16.27

    // 16.27 对于下面带标签的语句,解释发生什么样的实例化?(如果有的话)
    // 		 如果一个模版被实例化,解释为什么,如果没有,解释为什么没有
    
    template <typename T> class Stack { };
    
    void f1(Stack<char>);                   // (a)
    class Exercise {
        Stack<double> &rsd;                 // (b)
        Stack<int>    si;                   // (c)
    };
    int main() {
        Stack<char> *sc;                    // (d)
        f1(*sc);                            // (e)
        int iObj = sizeof(Stack< string >); // (f)
    }
    
    /*
    a. 没有,只是一个声明语句,当调用的时候实例化
    b. 没有,这里只是创建一个指针,不需要实例化
    c  有,这是一个非模板的类,创造对象
    d  没有,指针和引用不需要
    e  有   Stack<char>
    f  编译阶段实例化,但是只是临时的应该
    
    */
    
    // 测试方法
    // Solution from [How is a template instantiated? - Stack Overflow](https://stackoverflow.com/questions/21598635/how-is-a-template-instantiated)
    
    #include <iostream>
    using namespace std;
    
    
    template <typename T> class Stack {
      typedef typename T::ThisDoesntExist StaticAssert; // T::NotExisting doesn't exist at all!
    };
    
    
    void f1(Stack<char>); // No instantiation, compiles
    
    class Exercise {
      Stack<double> &rsd; // No instantiation, compiles (references don't need instantiation, are similar to pointers in this)
    
      Stack<int>    si; // Instantiation! Doesn't compile!!
    };
    
    
    int main(){
    
      Stack<char> *sc; // No Instantiation, this compiles successfully since a pointer doesn't need instantiation
    
      f1(*sc); // Instantiation of Stack<char>! Doesn't compile!!
    
      int iObj = sizeof(Stack< std::string >); // Instantiation of Stack<std::string>, doesn't compile!!
    
    }
    

    16.28

    // 16.28 编写自己的shared_ptr  和 unique_ptr
    // shared_ptr  保存一个指针,参数为value type*  按照delete是返回void的函数  using DelFuncPtr = void (*)(T*);
    // unique_ptr 保存的是删除器的类,因为不会被改变
    
    #include <vector>
    #include <string>
    #include <iostream>
    
    //*********************************************************************************************************
    /*
        0. 参考声明 template< class T > class shared_ptr;
        1. 内容指针,引用计数指针,删除器的函数指针
        2. 构造函数参考,先实现默认构造,即带一个指针和一个删除器
        3. 拷贝构造
        4. 拷贝赋值,这里需要释放原来的空间,可以使用 swap 传递值的方式 来实现
        5. 所以我们先实现swap   void swap( shared_ptr& r ) noexcept;
        6. 析构函数,判断引用,判断是否nullptr
        7. void reset( Y* ptr, Deleter d );
    */
    template <class T>
    class SharedPtr
    {
        using DelFuncPtr = void (*)(T *);
    
    private:
        T *ptr_ = nullptr;
        size_t *count_ptr_ = nullptr;
        DelFuncPtr del_ = nullptr;
    
    public:
        SharedPtr(T *ptr = nullptr, DelFuncPtr del = nullptr) : ptr_(ptr), del_(del), count_ptr_(new size_t(ptr_ != nullptr)) {}
        SharedPtr(const SharedPtr &s) : ptr_(s.ptr_), del_(s.del_), count_ptr_(s.count_ptr_)
        {
            ++*s.count_ptr_;
        }
        SharedPtr &operator=(SharedPtr s) //这里使用值传递,会先复制一份
        {
            //交换自己和临时的,临时的在退出的时候会自动调用析构释放
            swap(s);
            return *this;
        }
    
        void reset(T *ptr = nullptr, DelFuncPtr d = nullptr)
        {
            auto news = SharedPtr(ptr, d);
            swap(news);
        }
    
        void swap(SharedPtr &r) noexcept
        {
            using std::swap;
            swap(ptr_, r.ptr_);
            swap(count_ptr_, r.count_ptr_);
            swap(del_, r.del_);
        }
        ~SharedPtr()
        {
            if (ptr_ == nullptr)
                return;
            if (0 == --*count_ptr_)
            {
                del_ == nullptr ? delete (ptr_) : del_(ptr_);
                delete count_ptr_;
            }
            ptr_ = nullptr;
            count_ptr_ = nullptr;
        }
    
        T *get() const noexcept
        {
            return ptr_;
        }
    
        size_t use_count() const noexcept
        {
            return *count_ptr_;
        }
    
        T &operator*() const noexcept
        {
            return *ptr_;
        }
        T *operator->() const noexcept
        {
            return ptr_;
        }
        //检查 *this 是否存储非空指针,即是否有 get() != nullptr
        explicit operator bool() const noexcept
        {
            return get() != nullptr;
        }
    };
    
    //*********************************************************************************************************
    /**unique_ptr 保存的是删除器的类,因为不会被改变
     */
    
    class Delete
    {
    public:
        template <typename T>
        void operator()(T *ptr) const { delete ptr; }
    };
    
    template <typename T, typename D = Delete>
    class UniquePtr
    {
    private:
        T *ptr_ = nullptr;
        D del_;
    
    public:
        UniquePtr(T *ptr = nullptr, const D &d = D()) : ptr_(ptr), del_(d) {}
        ~UniquePtr() { del_(ptr_); }
        UniquePtr(const UniquePtr &) = delete;
        UniquePtr &operator=(const UniquePtr &) = delete;
    
        UniquePtr(UniquePtr &&other) noexcept : ptr_(other.ptr_), del_(std::move(other.del_))
        {
            other.ptr_ = nullptr;
        }
    
        UniquePtr &operator=(UniquePtr &&other) noexcept
        {
            if (this != &other)
            {
                reset();
                ptr_ = other.ptr_;
                del_ = std::move(other.del_);
                other.ptr_ = nullptr;
            }
            return *this;
        }
        UniquePtr &operator=(std::nullptr_t) noexcept
        {
            reset();
            return *this;
        }
        T *release() noexcept
        {
            T *ret = ptr_;
            ptr_ = nullptr;
            return ret;
        }
    
        void reset(T *ptr = nullptr)
        {
            del_(ptr_);
            ptr_ = ptr;
        }
    
        void swap(UniquePtr &other) noexcept
        {
            using std::swap;
            swap(ptr_, other.ptr_);
            swap(del_, other.del_);
        }
    
        T *get() const noexcept
        {
            return ptr_;
        }
    
        D &get_deleter() noexcept { return del_; }
        const D &get_deleter() const noexcept { return del_; }
    
        T &operator*() const noexcept
        {
            return *ptr_;
        }
        T *operator->() const noexcept
        {
            return ptr_;
        }
        T &operator[](size_t i) const { return ptr_[i]; }
        //检查 *this 是否存储非空指针,即是否有 get() != nullptr
        explicit operator bool() const noexcept
        {
            return get() != nullptr;
        }
    };
    //*********************************************************************************************************
    class DebugDelete
    {
    private:
        std::ostream &dbgos;
    
    public:
        DebugDelete(std::ostream &o = std::cout) : dbgos(o) {}
        template <typename T>
        void operator()(T *elem) const
        {
            dbgos << "delete by DebugDelete" << std::endl;
            delete elem;
        }
    };
    
    int main(int argc, const char **argv)
    {
        {
            using std::string;
            using std::vector;
            DebugDelete d;
    
            string *mystring = new string("123456");
    
            //SharedPtr<string> myshared_string(mystring, [](string *p) {std::cout << "Call delete from lambda...
    ";delete p; });
            SharedPtr<string> myshared_string(mystring, [](string *p) { DebugDelete()(p); });
            std::cout << *myshared_string.get() << std::endl;
    
            std::cout << "Test Copy assiment" << std::endl;
            SharedPtr<string> myshared_string3(new string("55555"));
            myshared_string3 = myshared_string;
    
            std::cout << "Test Copy Construct" << std::endl;
            SharedPtr<string> myshared_string2(myshared_string);
            std::cout << myshared_string.use_count() << std::endl;
        }
    
        {
            using std::string;
            using std::vector;
            std::cout << "Test Unique Ptr" << std::endl;
            UniquePtr<string> s1(new string("A10086"));
            std::cout << *s1.get() << std::endl;
    
            UniquePtr<string, DebugDelete> s2(new string("B10086"), DebugDelete());
            std::cout << *s1.get() << std::endl;
        }
        while (1)
            ;
        return 0;
    }
    

    16.29

    16.30

    // 修改你的Blob类,用你的shared_ptr 替代标准库的版本
    // 这里不能使用weak_ptr了,应该自己再做一个,
    // 在赋值迭代器的时候,weak_ptr 的赋值操作没有对 我们自己实现的 重载
    // 这里我们修改Blob 不使用迭代器了
    // 16.24 为你的Blob添加一个构造函数支持两个迭代器
    
    // 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员
    
    #include <vector>
    #include <memory>
    #include <string>
    #include <list>
    #include <iostream>
    #include <initializer_list>
    #include <exception>
    #include <algorithm>
    
    template <class T>
    class SharedPtr
    {
        using DelFuncPtr = void (*)(T *);
    
    private:
        T *ptr_ = nullptr;
        size_t *count_ptr_ = nullptr;
        DelFuncPtr del_ = nullptr;
    
    public:
        SharedPtr(T *ptr = nullptr, DelFuncPtr del = nullptr) : ptr_(ptr), del_(del), count_ptr_(new size_t(ptr_ != nullptr)) {}
        SharedPtr(const SharedPtr &s) : ptr_(s.ptr_), del_(s.del_), count_ptr_(s.count_ptr_)
        {
            ++*s.count_ptr_;
        }
        SharedPtr &operator=(SharedPtr s) //这里使用值传递,会先复制一份
        {
            //交换自己和临时的,临时的在退出的时候会自动调用析构释放
            swap(s);
            return *this;
        }
    
        void reset(T *ptr = nullptr, DelFuncPtr d = nullptr)
        {
            auto news = SharedPtr(ptr, d);
            swap(news);
        }
    
        void swap(SharedPtr &r) noexcept
        {
            using std::swap;
            swap(ptr_, r.ptr_);
            swap(count_ptr_, r.count_ptr_);
            swap(del_, r.del_);
        }
        ~SharedPtr()
        {
            if (ptr_ == nullptr)
                return;
            if (0 == --*count_ptr_)
            {
                del_ == nullptr ? delete (ptr_) : del_(ptr_);
                delete count_ptr_;
            }
            ptr_ = nullptr;
            count_ptr_ = nullptr;
        }
    
        T *get() const noexcept
        {
            return ptr_;
        }
    
        size_t use_count() const noexcept
        {
            return *count_ptr_;
        }
    
        T &operator*() const noexcept
        {
            return *ptr_;
        }
        T *operator->() const noexcept
        {
            return ptr_;
        }
        //检查 *this 是否存储非空指针,即是否有 get() != nullptr
        explicit operator bool() const noexcept
        {
            return get() != nullptr;
        }
    };
    
    template <typename T>
    class Blob;
    
    template <typename T>
    bool operator==(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator!=(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator<(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator>(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator<=(const Blob<T> &a, const Blob<T> &b);
    template <typename T>
    bool operator>=(const Blob<T> &a, const Blob<T> &b);
    
    template <typename T>
    class Blob
    {
    
        friend bool operator==<T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator!=<T>(const Blob<T> &a, const Blob<T> &b);
        // clang-format off
        friend bool operator< <T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator> <T>(const Blob<T> &a, const Blob<T> &b);
        // clang-format on
        friend bool operator<=<T>(const Blob<T> &a, const Blob<T> &b);
        friend bool operator>=<T>(const Blob<T> &a, const Blob<T> &b);
    
        // 以下两个应该是为了外部方便获取类型
        typedef T value_type;
        typedef typename std::vector<T>::size_type size_type;
    
    private:
        SharedPtr<std::vector<T>> data;
        void check(size_type i, const std::string &msg) const;
    
    public:
        Blob() : data(new std::vector<T>()) {}
        // 16.24
        template <typename type_it>
        Blob(type_it a, type_it b) : data(new std::vector<T>(a, b)) {}
    
        Blob(const Blob<T> &s) : data(new std::vector<T>(*s.data)) {}
        Blob(Blob<T> &&a) noexcept : data(std::move(a.data)) {}
    
        Blob &operator=(const Blob<T> &s);
        Blob &operator=(Blob<T> &&) noexcept;
    
        Blob(std::initializer_list<T> il) : data(new std::vector<T>(il)) {}
        size_type size() const { return data->size(); }
        bool empty() const { return data->empty(); }
    
        void push_back(T &val) { data->push_back(val); };
        void push_back(const T &val) { data->push_back(std::move(val)); }
        void pop_back();
    
        T &back();
        const T &back() const;
        T &front();
        const T &front() const;
    
        T &operator[](size_type i);
        const T &operator[](size_type i) const;
    
        void print(std::ostream &o);
    };
    
    template <typename T>
    Blob<T> &Blob<T>::operator=(const Blob<T> &s)
    {
        data = new std::vector<T>(*s.data);
        return *this;
    }
    
    template <typename T>
    Blob<T> &Blob<T>::operator=(Blob<T> &&s) noexcept
    {
        if (this != s)
        {
            data = std::move(s.data);
            s.data = nullptr;
        }
        return *this;
    }
    
    template <typename T>
    void Blob<T>::print(std::ostream &o)
    {
        for (auto ch : (*data))
            o << ch << ",";
        o << std::endl;
    }
    
    template <typename T>
    void Blob<T>::check(size_type i, const std::string &msg) const
    {
        if (i >= size())
        {
            throw std::out_of_range(msg);
        }
    }
    
    template <typename T>
    void Blob<T>::pop_back()
    {
        check(0, "empty to pop_back");
        data->pop_back();
    }
    
    template <typename T>
    T &Blob<T>::back()
    {
        check(0, "Get empty Back()");
        return data->back();
    }
    template <typename T>
    const T &Blob<T>::back() const
    {
        check(0, "Get empty Back()");
        return data->back();
    }
    
    template <typename T>
    T &Blob<T>::front()
    {
        check(0, "Get empty front()");
        return data->front();
    }
    template <typename T>
    const T &Blob<T>::front() const
    {
        check(0, "Get empty front()");
        return data->front();
    }
    
    template <typename T>
    T &Blob<T>::operator[](size_type i)
    {
        check(i, "Get [" + std::to_string(i) + "]");
        return data->at(i);
    }
    
    template <typename T>
    const T &Blob<T>::operator[](size_type i) const
    {
        check(i, "Get [" + std::to_string(i) + "]");
        return data->at(i);
    }
    
    //****************************************************************************
    template <typename T>
    bool operator==(const Blob<T> &a, const Blob<T> &b)
    {
        return (*a.data == *b.data);
    }
    template <typename T>
    bool operator!=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(a == b);
    }
    
    template <typename T>
    bool operator<(const Blob<T> &a, const Blob<T> &b)
    {
        return std::lexicographical_compare(a.data->begin(), a.data->end(), b.data->begin(), b.data->end());
    }
    
    template <typename T>
    bool operator>(const Blob<T> &a, const Blob<T> &b)
    {
        return (b < a);
    }
    template <typename T>
    bool operator<=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(b > a);
    }
    template <typename T>
    bool operator>=(const Blob<T> &a, const Blob<T> &b)
    {
        return !(a < b);
    }
    
    int main(int argc, const char **argv)
    {
        Blob<std::string> blob_s({"1", "2"});
        blob_s.print(std::cout);
        while (1)
            ;
        return 0;
    }
    

    16.31

    // 16.31 如果我们将DebugDelete 与 unique_ptr 一起使用,解释编译器将删除器处理为内联形式的可能?
    // The compiler will set the default deleter type as `DebugDelete`, 
    // which will be executed is known at compile time.
    编译的时候就传递赋值
    

    16.32

    // 在模版实参推断过程中发生了什么?
    1. 类型推导
    2. 实例化函数
    

    16.33

    指出在模版实参推断过程中允许对函数实参进行的两种类型转换。
    1. const转换, 实参是非const的传递给形参是const的
    2. 数组或函数转换为指针,注意:形参不能是引用,形参是引用,传递的是数组,含有纬度的
    

    16.34

    对下面的代码解释每个调用是否合法。如果合法,T 的类型是什么?如果不合法,为什么?
    template <class T> int compare(const T&, const T&);
    (a) compare("hi", "world");
    (b) compare("bye", "dad");
    
    a. 不合法,这里传递的是char(&a)[3] char(&a)[6]
    b. 合法
    

    13.35

    13.35 下面调用中哪些是错误的(如果有的话)?如果调用合法,T 的类型是什么?如果调用不合法,问题何在?
    
    
    template <typename T> T calc(T, int);
    tempalte <typename T> T fcn(T, T);
    double d; float f; char c;
    (a) calc(c, 'c'); 
    (b) calc(d, f);
    (c) fcn(c, 'c');
    (d) fcn(d, f);
    
    a. 合法, T=char
    b. 合法,T=double
    c  合法 char,
    d  不合法,不能发生类型转换
    
    

    16.36

    // 进行下面的调用会发生什么
    template <typename T> f1(T, T);
    template <typename T1, typename T2) f2(T1, T2);
    int i = 0, j = 42, *p1 = &i, *p2 = &j;
    const int *cp1 = &i, *cp2 = &j;
    (a) f1(p1, p2);
    (b) f2(p1, p2);
    (c) f1(cp1, cp2);
    (d) f2(cp1, cp2);
    (e) f1(p1, cp1);
    (f) f2(p1, cp1);
    
    // f1没有返回值  哈哈哈
    a. f1(int*,int*);
    b. f2(int*,int*);
    c. f1(const int*,const int*);
    d. f2(const int*,const int*);
    e. error
    f. f2( int*,const int*);
    

    16.37

    标准库 max 函数有两个参数,它返回实参中的较大者。此函数有一个模版类型参数。
    你能在调用 max 时传递给它一个 int 和一个 double 吗?如果可以,如何做?如果不可以,为什么?
    
    
    
    指定参数类型 max<double>(a, b);
    
    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;
    int main(int argc, char const *argv[])
    {
        int a = 6;
        double b = 6.1231;
        std::cout << std::max<long double>(a, b) << std::endl;
        // initializer_list<T> 也是模版,不会发生转换
        //std::cout << std::max({a, b}, [](const int a, const int b) { return a < b; }) << std::endl;
        std::cout << std::max({1, 2}, [](const int a, const int b) { return a < b; }) << std::endl;
    
        while (1)
            ;
        return 0;
    }
    

    16.38

    当我们调用 make_shared 时,必须提供一个显示模版实参。解释为什么需要显式模版实参以及它是如果使用的。
    
    返回类型无法推断
    

    16.39

    对16.1.1节 578 中的原始版本的 compare 函数,使用一个显式模版实参,使得可以向函数传递两个字符串字面量。
    compare<std::string>("a", "bb");
    

    16.40

    下面的函数是否合法?如果不合法,为什么?如果合法,对可以传递的实参类型有什么限制(如果有的话)?
    返回类型是什么?
    
    合法,元素支持+ 返回类型由operator+决定
    template <typename It>
    auto fcn3(It beg, It end) -> decltype(*beg + 0)
    {
    	//处理序列
    	return *beg;
    }
    
    

    16.41

    编写一个新的 sum 版本,它返回类型保证足够大,足以容纳加法结果
    
    template <typename T1, typename T2>
    auto sum(T1 a, T2 b) -> decltype(a + b) {
        return a + b;
    }
    

    16.42

    // 对下面每个调用,确定 T 和 val 的类型:
    template <typename T> void g(T&& val);
    int i = 0; const int ci = i;
    (a) g(i);
    (b) g(ci);
    (c) g(i * ci);
    
    a. i是左值,所以会传递左值引用 int& && 折叠为 int&
    b. ci 是const int, 折叠为const int&
    c. i*ci是一个局部的变量,是个右值int&& 折叠为int&&
    
    

    16.43

    使用上一题定义的函数,如果我们调用g(i = ci),g 的模版参数将是什么?
    i=ci 返回的是 i 也就是 int,折叠为int&
    
    #include <iostream>
    
    int main(int argc, char const *argv[])
    {
        int i = 0;
        ++(i = 3);
        std::cout << i << std::endl;	//4
    
        while (1)
            ;
        return 0;
    }
    

    16.44

    使用与第一题中相同的三个调用,如果 g 的函数参数声明为 T(而不是T&&),确定T的类型。
    如果g的函数参数是 const T&呢?
    
    
    template <typename T> void g(T val);
    int i = 0; const int ci = i;
    (a) g(i);    		int
    (b) g(ci);   		int 
    (c) g(i * ci);		int
    
    
    template <typename T> void g(const& val);
    int i = 0; const int ci = i;
    (a) g(i);    		 int 
    (b) g(ci);   		 int 
    (c) g(i * ci);		 int 
    
    
    

    16.45

    如果下面的模版,如果我们对一个像42这样的字面常量调用g,解释会发生什么?
    如果我们对一个int 类型的变量调用g 呢?
    
    template <typename T> void g(T&& val) { vector<T> v; }
    
    g(42)	传递的就是 int&& 
    {
        vector<int&&> v;
    }
    
    int i;
    g(i) // 传递是 int& && 折叠为 int&
    {
        vector<int&> v; //报错,无法保存引用
    }
    

    16.46

    // 解释下面的循环,它来自13.5节中的 StrVec::reallocate:
    // alloc.construct(dest++, std::move(*elem++));
    
    // *elem 为左值,转换为 elem的右值
    template< class U, class... Args >
    void construct( U* p, Args&&... args );
    
    

    16.47

    #include <iostream>
    
    void f(int v1, int &v2)
    {
        std::cout << v1 << " " << ++v2 << std::endl;
    }
    
    void g(int &&i, int &j)
    {
        std::cout << i << " " << ++j << std::endl;
    }
    
    template <typename F, typename T1, typename T2>
    void flip(F f, T1 &&t1, T2 &&t2)
    {
        f(std::forward<T2>(t2), std::forward<T1>(t1));
    }
    
    int main()
    {
        int j = 0;
        flip(f, j, 42);
        flip(g, j, 42);
        while (1)
            ;
    }
    

    16.48

    // 16.48 编写你自己版本的 debug_rep 函数。
    
    #include <iostream>
    #include <string>
    #include <sstream>
    using std::string;
    
    template <typename T>
    string debug_rep(const T &t)
    {
        std::ostringstream ret;
        ret << t;
        return ret.str();
    }
    
    template <typename T>
    string debug_rep(T *t)
    {
        std::ostringstream ret;
        ret << "Point Addr=" << t;
        if (t == nullptr)
            ret << "nullptr";
        else
            ret << debug_rep(*t);
        return ret.str();
    }
    
    string debug_rep(const string &t)
    {
        return "String:" + t;
    }
    
    string debug_rep(char *t)
    {
        return "char*" + debug_rep(string(t));
    }
    
    string debug_rep(const char *t)
    {
        return "const char*" + debug_rep(string(t));
    }
    
    int main(int argc, const char **argv)
    {
    
        std::cout << debug_rep("123456") << std::endl;
        while (1)
            ;
    
        return 0;
    }
    
    

    16.49

    //16.49解释下面每个调用会发生什么
    template <typename T> void f(T);
    template <typename T> void f(const T*);
    template <typename T> void g(T);
    template <typename T> void g(T*);
    int i = 42, *p = &i;
    const int ci = 0, *p2 = &ci;
    g(42); g(p); g(ci); g(p2);
    f(42); f(p); f(ci); f(p2);
    
    
    g(42)   T=int  			3.template <typename T> void g(T);
    g(p) 	T=int			4.template <typename T> void g(T*);
    g(ci)	T=const int		3.template <typename T> void g(T);
    g(p2)	T=const int		4.template <typename T> void g(T*);
    
    f(42)	T=int			1.template <typename T> void f(T);
    f(p)	T=int*			1.template <typename T> void f(T);
    f(ci)	T=const int		1.template <typename T> void f(T);
    f(p2)   T=int			2.template <typename T> void f(const T*);
    

    16.50

    // 16.50 定义上一个练习中的函数,令它们打印一条身份信息。运行该练习中的代码。如果函数调用的行为与你预期不符,确定你理解了原因。
    /*
    template <typename T> void f(T);
    template <typename T> void f(const T*);
    template <typename T> void g(T);
    template <typename T> void g(T*);
    int i = 42, *p = &i;
    const int ci = 0, *p2 = &ci;
    g(42); g(p); g(ci); g(p2);
    f(42); f(p); f(ci); f(p2);
    
    
    g(42)   T=int  			3.template <typename T> void g(T);
    g(p) 	T=int			4.template <typename T> void g(T*);
    g(ci)	T=const int		3.template <typename T> void g(T);
    g(p2)	T=const int		4.template <typename T> void g(T*);
    
    f(42)	T=int			1.template <typename T> void f(T);
    f(p)	T=int*			1.template <typename T> void f(T);
    f(ci)	T=const int		1.template <typename T> void f(T);
    f(p2)   T=int			2.template <typename T> void f(const T*);
    */
    #include <iostream>
    #include <string>
    
    template <typename T>
    void f(T)
    {
        std::cout << "1" << std::endl;
    }
    template <typename T>
    void f(const T *)
    {
        std::cout << "2" << std::endl;
    }
    template <typename T>
    void g(T)
    {
        std::cout << "3" << std::endl;
    }
    template <typename T>
    void g(T *)
    {
        std::cout << "4" << std::endl;
    }
    
    int main(int argc, char const *argv[])
    {
        int i = 42, *p = &i;
        const int ci = 0, *p2 = &ci;
        g(42);
        g(p);
        g(ci);
        g(p2);
        f(42);
        f(p);
        f(ci);
        f(p2);
    
        while (1)
            ;
        return 0;
    }
    
    

    16.51

    16.52

    // 16.51 调用本节中的每个 foo,确定 sizeof…(Args) 和 sizeof…(rest)分别返回什么。
    #include <iostream>
    using namespace std;
    
    template <typename T, typename... Args>
    void foo(const T &t, const Args &... rest)
    {
        std::cout << "sizeof...(Args)=" << sizeof...(Args) << "  sizeof...(rest)=" << sizeof...(rest) << std::endl;
    }
    
    int main(int argc, const char **argv)
    {
        int i = 0;
        double d = 3.14;
        string s = "how";
    
        foo(i, s, 42, d);       /// sizeof...(Args)=3  sizeof...(rest)=3
        foo(s, 42, "hi");       /// sizeof...(Args)=2  sizeof...(rest)=2
        foo(d, s);              /// sizeof...(Args)=1  sizeof...(rest)=1
        foo("hi");              /// sizeof...(Args)=0  sizeof...(rest)=0
        foo(i, s, s, d);        /// sizeof...(Args)=3  sizeof...(rest)=3
    
        while (1)
            ;
        return 0;
    }
    
    

    16.53

    // 16.53 编写你自己版本的 print 函数,并打印一个、两个及五个实参来测试它,要打印的每个实参都应有不同的类型。
    
    #include <iostream>
    using namespace std;
    
    template <typename T>
    ostream &print(ostream &o, const T &s)
    {
        return o << s << endl;
    }
    
    template <typename A, typename... T>
    ostream &print(ostream &o, const A &a, const T &... s)
    {
        o << a << ",";
        return print(o, s...);
    }
    
    int main(int argc, const char **argv)
    {
        int i = 1;
        double d = 3.14;
        float f = 99.99;
        string s = "hello";
    
        print(std::cout, i);
        print(std::cout, i, s);
        print(std::cout, i, d, f, s, "123456");
    
        while (1)
            ;
    
        return 0;
    }
    

    16.54

    如果我们对一个没 << 运算符的类型调用 print,会发生什么?
    编译实例化失败.
        //no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'const std::vector<int>')
        //print(std::cout, i, d, f, s, vector<int>(1));
    

    16.55

    // 如果我们的可变参数版本 print 的定义之后声明非可变参数版本,解释可变参数的版本会如何执行。
    我们最终会执行到只有 ostream,没有第二个参数 print(std::ostream&)
    但是我们的模版函数是 ostream &print(ostream &o, const A &a, const T &... s)
    也就是没有匹配一个参数的版本
    

    16.56

    // 16.56 编写并测试可变参数版本的 errorMsg。
    #include <initializer_list>
    #include <iostream>
    #include <string>
    #include <sstream>
    using namespace std;
    
    /*********************************************************************/
    template <typename T>
    string debug_rep(const T &t)
    {
        std::ostringstream ret;
        ret << t;
        return ret.str();
    }
    
    template <typename T>
    string debug_rep(T *t)
    {
        std::ostringstream ret;
        ret << "Point Addr=" << t;
        if (t == nullptr)
            ret << "nullptr";
        else
            ret << debug_rep(*t);
        return ret.str();
    }
    
    string debug_rep(const string &t)
    {
        return "String:" + t;
    }
    
    string debug_rep(char *t)
    {
        return "char*" + debug_rep(string(t));
    }
    
    string debug_rep(const char *t)
    {
        return "const char*" + debug_rep(string(t));
    }
    
    /*********************************************************************/
    
    void err_msg_old(initializer_list<string> il)
    {
        for (auto ch : il)
            std::cout << ch << ",";
        std::cout << std::endl;
    }
    
    template <typename T>
    ostream &print(ostream &o, const T &s)
    {
        return o << s << endl;
    }
    template <typename A, typename... T>
    ostream &print(ostream &o, const A &a, const T &... s)
    {
        o << a << ",";
        return print(o, s...);
    }
    
    template <typename... T>
    ostream &err_msg(ostream &o = std::cout, const T &... s)
    {
        // 这里会展开  debug_rep(int) debug_rep(char)
        return print(o, debug_rep(s)...);
    }
    
    int main(int argc, char const *argv[])
    {
        err_msg_old({"1", "2", "3"});
        err_msg(std::cout, "1", 1, 3.14);
        while (1)
            ;
        return 0;
    }
    
    

    16.57

    可变参数的比较灵活,但是要用比较多的堆栈估计
    简单版本的,代码简单,方便调试
    

    16.58

    // 16.58 你的 StrVec 类及你为16.1.2节练习中编写的 Vec 类添加 emplace_back 函数。
    // template< class... Args >
    // void emplace_back( Args&&... args );
    
    /*
        template <class... Args>
        T *emplace_back(Args &&... args)
        {
            chk_n_alloc();
            alloc.construct(first_free++, std::forward<Args>(args)...);
        }
    
        std::string its = "my_name_is_yer";
        vec.emplace_back(its.begin(), its.end());
        vec.emplace_back("back_123");
        vec.emplace_back(20, 'c');
    
    */
    
    // 16.16 定义模版类的vec 替代之前的Strvec
    
    #include <memory>
    #include <algorithm>
    #include <utility>
    #include <initializer_list>
    #include <exception>
    #include <string>
    #include <stdexcept>
    #include <iostream>
    // using std::cin;
    // using std::cout;
    // using std::endl;
    
    // 定义一些公共操作
    // 从一个迭代器范围复制 到指定的位置,返回内存的首地址和尾地址+1 也就是返回 begin和end
    
    /**
     如何设计一个 vector
     1. 首先我们定义一个分配器,一个首地址,尾地址,以及容量
     2. 提供 size,begin,end,capacity,at,[]
     3. push_back
            chk_n_alloc();
            3.1 检查容量的操作
            3.2 容量的分配,这里需要设计一个移动函数    
            alloc.construct
            3.3 数据构造 
     4. 移动函数涉及
            alloc_n_move
            4.1 内存分配
            4.2 原来数据的移动
     5.设计reserve
            5.1 内存分配和移动 alloc_n_move
     6.设计resize
        重设容器大小以容纳 count 个元素。
    
        若当前大小大于 count ,则减小容器为其首 count 个元素。
        设置指针,调用元素的析构函数 destroy析构在已分配存储中的对象 
    
        若当前大小小于 count ,则后附额外元素,并以 value 的副本初始化。
        也就是调用reserve
    
    
    */
    
    template <typename>
    class Vec;
    
    template <typename T>
    bool operator==(const Vec<T> &, const Vec<T> &);
    template <typename T>
    bool operator!=(const Vec<T> &, const Vec<T> &);
    template <typename T>
    bool operator<(const Vec<T> &, const Vec<T> &);
    template <typename T>
    bool operator>(const Vec<T> &, const Vec<T> &);
    template <typename T>
    bool operator<=(const Vec<T> &, const Vec<T> &);
    template <typename T>
    bool operator>=(const Vec<T> &, const Vec<T> &);
    
    template <typename T>
    class Vec
    {
        friend bool operator==<T>(const Vec<T> &, const Vec<T> &);
        friend bool operator!=<T>(const Vec<T> &, const Vec<T> &);
        // clang-format off
        friend bool operator< <T>(const Vec<T>&, const Vec<T>&);
        friend bool operator> <T>(const Vec<T>&, const Vec<T>&);
        // clang-format on
        friend bool operator<=<T>(const Vec<T> &, const Vec<T> &);
        friend bool operator>=<T>(const Vec<T> &, const Vec<T> &);
    
    private:
        T *elements;
        T *first_free;
        T *cap;
        std::allocator<T> alloc;
    
        std::pair<T *, T *> alloc_n_copy(const T *b, const T *e);
        void range_initialize(const T *first, const T *last);
        void free();
        void reallocate();
        void alloc_n_move(size_t new_cap);
        void chk_n_alloc()
        {
            if (size() == capacity())
                reallocate();
        }
    
    public:
        Vec(std::initializer_list<T>);
        Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
        Vec(const Vec<T> &);
        //------------------------------------------------------------Vec<T> &operator=(const Vec<T> &s);
        Vec &operator=(const Vec<T> &s);
        Vec(Vec<T> &&) noexcept;
        Vec &operator=(Vec<T> &&) noexcept;
    
        T *begin() const { return elements; }
        T *end() const { return first_free; }
        T &at(size_t pos) { return *(elements + pos); }
        const T &at(size_t pos) const { return *(elements + pos); }
    
        T &operator[](size_t n) { return elements[n]; }
        const T &operator[](size_t n) const { return elements[n]; }
    
        void push_back(const T &);
        size_t size() const { return first_free - elements; }
        size_t capacity() const { return cap - elements; }
    
        void reserve(size_t new_cap);
        void resize(size_t count);
        void resize(size_t count, const T &);
    
        template <class... Args>
        T *emplace_back(Args &&... args)
        {
            chk_n_alloc();
            alloc.construct(first_free++, std::forward<Args>(args)...);
        }
    
        ~Vec();
    };
    
    template <typename T>
    std::pair<T *, T *> Vec<T>::alloc_n_copy(const T *b, const T *e)
    {
        auto data = alloc.allocate(e - b);
        return {data, std::uninitialized_copy(b, e, data)};
    }
    
    template <typename T>
    void Vec<T>::range_initialize(const T *first, const T *last)
    {
        auto newdata = alloc_n_copy(first, last);
        elements = newdata.first;
        first_free = cap = newdata.second;
    }
    template <typename T>
    void Vec<T>::free()
    {
        if (elements)
        {
            //执行元素的析构函数
            for_each(elements, first_free, [this](T &rhs) { alloc.destroy(&rhs); });
            //释放vector内存
            alloc.deallocate(elements, cap - elements);
        }
    }
    
    template <typename T>
    Vec<T>::Vec(std::initializer_list<T> il)
    {
        range_initialize(il.begin(), il.end());
    }
    template <typename T>
    Vec<T>::Vec(const Vec<T> &s)
    {
        range_initialize(s.begin, s.end);
    }
    
    template <typename T>
    Vec<T> &Vec<T>::operator=(const Vec<T> &s)
    {
        if (this != s)
        {
            auto data = alloc_n_copy(s.begin(), s.end());
            free();
            elements = data.first;
            first_free = cap = data.second;
        }
        return *this;
    }
    template <typename T>
    Vec<T>::Vec(Vec<T> &&s) noexcept
    {
        elements = s.elements;
        first_free = s.first_free;
        cap = s.cap;
        s.elements = s.first_free = s.cap = nullptr;
    }
    template <typename T>
    Vec<T> &Vec<T>::operator=(Vec<T> &&s) noexcept
    {
        if (this != &s)
        {
            free();
            elements = s.elements;
            first_free = s.first_free;
            cap = s.cap;
            s.elements = s.first_free = s.cap = nullptr;
        }
        return *this;
    }
    
    template <typename T>
    Vec<T>::~Vec()
    {
        free();
    }
    
    template <typename T>
    void Vec<T>::alloc_n_move(size_t new_cap)
    {
        auto newdata = alloc.allocate(new_cap);
        auto dest = newdata;
        auto elem = elements;
        for (size_t i = 0; i != size(); ++i)
            alloc.construct(dest++, std::move(*elem++));
        free();
        elements = newdata;
        first_free = dest;
        cap = elements + new_cap;
    }
    template <typename T>
    void Vec<T>::reallocate()
    {
        auto newcapacity = size() ? 2 * size() : 1;
        alloc_n_move(newcapacity);
    }
    template <typename T>
    void Vec<T>::reserve(size_t new_cap)
    {
        if (new_cap <= capacity())
            return;
        alloc_n_move(new_cap);
    }
    
    // resize
    // 重设容器大小以容纳 count 个元素。
    // 若当前大小大于 count ,则减小容器为其首 count 个元素。
    // 若当前大小小于 count ,则后附额外元素,并以 value 的副本初始化。
    template <typename T>
    void Vec<T>::resize(size_t count, const T &s)
    {
        if (count > size())
        {
            if (count > capacity())
                reserve(count * 2);
            for (size_t i = size(); i != count; ++i)
                alloc.construct(first_free++, s);
        }
        else if (count < size())
        {
            while (first_free != elements + count)
                alloc.destroy(--first_free);
        }
    }
    
    template <typename T>
    void Vec<T>::resize(size_t count)
    {
        resize(count, T());
    }
    
    template <typename T>
    void Vec<T>::push_back(const T &s)
    {
        chk_n_alloc();
        alloc.construct(first_free++, s);
    }
    
    //------------------------------------------------------------------------------
    //------------------------------------------------------------------------------
    //------------------------------------------------------------------------------
    template <typename T>
    bool operator==(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return (lhs.size() == rhs.size() &&
                std::equal(lhs.begin(), lhs.end(), rhs.begin()));
    }
    
    template <typename T>
    bool operator!=(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return !(lhs == rhs);
    }
    
    template <typename T>
    bool operator<(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
                                            rhs.end());
    }
    
    template <typename T>
    bool operator>(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return rhs < lhs;
    }
    
    template <typename T>
    bool operator<=(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return !(rhs < lhs);
    }
    
    template <typename T>
    bool operator>=(const Vec<T> &lhs, const Vec<T> &rhs)
    {
        return !(lhs < rhs);
    }
    int main()
    {
        Vec<std::string> vec;
        vec.reserve(6);
        std::cout << "capacity(reserve to 6): " << vec.capacity() << std::endl;
    
        vec.reserve(4);
        std::cout << "capacity(reserve to 4): " << vec.capacity() << std::endl;
    
        vec.push_back("hello");
        vec.push_back("world");
    
        vec.resize(4);
    
        std::string its = "my_name_is_yer";
        vec.emplace_back(its.begin(), its.end());
        vec.emplace_back("back_123");
        vec.emplace_back(20, 'c');
    
        for (auto i = vec.begin(); i != vec.end(); ++i)
            std::cout << *i << std::endl;
        std::cout << "-EOF-" << std::endl;
    
        vec.resize(1);
    
        for (auto i = vec.begin(); i != vec.end(); ++i)
            std::cout << *i << std::endl;
        std::cout << "-EOF-" << std::endl;
    
        Vec<std::string> vec_list{"hello", "world", "pezy"};
    
        for (auto i = vec_list.begin(); i != vec_list.end(); ++i)
            std::cout << *i << " ";
        std::cout << std::endl;
    
        // Test operator==
    
        const Vec<std::string> const_vec_list{"hello", "world", "pezy"};
        if (vec_list == const_vec_list)
            for (const auto &str : const_vec_list)
                std::cout << str << " ";
        std::cout << std::endl;
    
        // Test operator<
        const Vec<std::string> const_vec_list_small{"hello", "pezy", "ok"};
        std::cout << (const_vec_list_small < const_vec_list) << std::endl;
    
        // Test []
        std::cout << const_vec_list_small[1] << std::endl;
        while (1)
            ;
    }
    

    16.59

    // 假定 s 是一个 string,解释调用 svec.emplace_back(s)会发生什么
    1.转发扩展包
    2. s 传递是值传递,也就是会调用string newstring(s),拷贝构造函数
    

    16.60

    // 解释 make_shared 是如何工作的。
    最简单的一种重载是
    template< class T, class... Args >
    shared_ptr<T> make_shared( Args&&... args );
    
    我们在使用的时候, shared_ptr<string> a=make_shared<string>("123");
    
    1. 转发扩展包给 class T 的构造函数
    2. 内部提取地址到shared<T> 
        
    

    16.61

    // 解释 make_shared 是如何工作的。
    // 最简单的一种重载是
    // template< class T, class... Args >
    // shared_ptr<T> make_shared( Args&&... args );
    
    // 我们在使用的时候, shared_ptr<string> a=make_shared<string>("123");
    
    // 1. 转发扩展包给 class T 的构造函数
    // 2. 内部提取地址到shared<T>
    
    #include <memory>
    #include <string>
    #include <iostream>
    using namespace std;
    
    template <class T, class... Args>
    shared_ptr<T> my_make_shared(Args &&... args)
    {
        shared_ptr<T> ret(new T(std::forward<Args>(args)...));
    
        return ret;
    }
    
    int main(int argc, char const *argv[])
    {
        shared_ptr<string> s1 = my_make_shared<string>("123");
        std::cout << *s1 << std::endl;
        while (1)
            ;
        return 0;
    }
    
    

    16.62

    // 16.62 定义你自己版本的 hash<Sales_data>, 并定义一个 Sales_data 对象的 unorder_multise。将多条交易记录保存到容器中,并打印其内容
    // p396
    // 无序容器需要提供 元素的== 以及哈希函数
    // 需要提供hash<类型>的模版,一个 ()运算返回size_t 表示hash值
    #include <string>
    #include <vector>
    #include <iostream>
    #include <unordered_set>
    using namespace std;
    
    class Sales_data
    {
        friend bool operator==(const Sales_data &, const Sales_data &);
        friend std::hash<Sales_data>;
    
    private:
        string isbn;
        unsigned units_sold = 0;
        double revenue = 0.0;
    
    public:
        Sales_data(string isbn, unsigned units_sold, double revenue) : isbn(isbn), units_sold(units_sold), revenue(revenue) {}
    
        double avg_price() { return revenue / units_sold; }
        void print() { std::cout << "name=" << isbn << " aver_price= " << avg_price() << std::endl; }
        string prints() { return string("name=") + isbn + " aver_price= " + to_string(avg_price()); }
    };
    
    bool operator==(const Sales_data &a, const Sales_data &b)
    {
        return (a.isbn == b.isbn) && (a.revenue == b.revenue) && (a.units_sold == b.units_sold);
    }
    
    namespace std
    {
    template <>
    struct hash<Sales_data>
    {
        typedef size_t result_type;
        typedef Sales_data argument_type;
        size_t operator()(const Sales_data &s) const
        {
            return hash<string>()(s.isbn) ^
                   hash<unsigned>()(s.units_sold) ^
                   hash<double>()(s.revenue);
        }
    };
    } // namespace std
    
    int main(int argc, const char **argv)
    {
        Sales_data A1("A1", 5, 17);
        A1.print();
    
        std::unordered_multiset<Sales_data> mset;
    
        mset.emplace(A1);
        mset.emplace("C++ Primer", 5, 9.99);
    
        for (auto ch : mset)
            std::cout << "hash()=" << std::hex << std::hash<Sales_data>()(ch) << ch.prints() << std::endl;
    
        while (1)
            ;
        return 0;
    }
    

    16.63

    16.64

    
    // 16.64 为上一题的模版编写特例化版本来处理vector<const char*>。编写程序使用这个特例化版本。
    // 16.63 定义一个函数模版,统计一个给定值在一个vecor中出现的次数。
    // 测试你的函数,分别传递给它一个double的vector,一个int的vector以及一个string的vector。
    
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    template <typename T>
    int GetCount(T elem, const vector<T> &v)
    {
        std::cout << __LINE__ << "   :GetCount(T elem, const vector<T> &v)" << std::endl;
        int i = 0;
        for (auto ch : v)
        {
            if (ch == elem)
                i++;
        }
        return i;
    }
    
    template <>
    int GetCount(const char *elem, const vector<const char *> &v)
    {
        std::cout << __LINE__ << "   :GetCount(const char *elem, const vector<const char *> &v)" << std::endl;
        int i = 0;
        for (auto ch : v)
        {
            if (string(ch) == string(elem))
                i++;
        }
        return i;
    }
    
    int GetCount(const char *elem, const vector<string> &v)
    {
        std::cout << __LINE__ << "    :GetCount(const char *elem, const vector<string> &v)" << std::endl;
        return GetCount(string(elem), v);
    }
    
    int GetCount(const int elem, const vector<double> &v)
    {
        return GetCount((double)elem, v);
    }
    
    int main(int argc, char const *argv[])
    {
        vector<string> s({"123", "456", "789", "123", "222"});
        std::cout << GetCount("123", s) << std::endl;
        std::cout << GetCount(string("123"), s) << std::endl;
    
        vector<int> i = {1, 2, 3, 4, 5, 6, 1, 2};
        std::cout << GetCount(1, i) << std::endl;
    
        // vector<double> d = {1.0, 2.5, 3, 4, 5, 6, 1, 2};
        // std::cout << GetCount(1, d) << std::endl;
    
        vector<const char *> s3({"123", "456", "789", "123", "222"});
        std::cout << GetCount("123", s3) << std::endl;
    
        while (1)
            ;
        return 0;
    }
    
    

    16.65

    // 在16.3节中我们定义了两个重载的 debug_rep 版本,一个接受 const char* 参数,另一个接受 char * 参数。将这两个函数重写为特例化版本。
    // 16.48 编写你自己版本的 debug_rep 函数。
    
    #include <iostream>
    #include <string>
    #include <sstream>
    using std::string;
    
    string debug_rep(const string &t)
    {
        return "String:" + t;
    }
    
    template <typename T>
    string debug_rep(const T &t)
    {
        std::ostringstream ret;
        ret << t;
        return ret.str();
    }
    
    template <typename T>
    string debug_rep(T *t)
    {
        std::ostringstream ret;
        ret << "Point Addr=" << t;
        if (t == nullptr)
            ret << "nullptr";
        else
            ret << debug_rep(*t);
        return ret.str();
    }
    template <>
    string debug_rep(const char *t)
    {
        return string("const char*") + debug_rep(string(t));
    }
    template <>
    string debug_rep(char *t)
    {
        return "char*" + debug_rep(string(t));
    }
    
    // string debug_rep(const char *t)
    // {
    //     return "const char*" + debug_rep(string(t));
    // }
    
    int main(int argc, const char **argv)
    {
    
        std::cout << debug_rep("123456") << std::endl;
        while (1)
            ;
    
        return 0;
    }
    
    

    16.66

    重载debug_rep 函数与特例化它相比,有何优点和缺点?
    
    特例化是的本质是实例化一个模版,不影响函数匹配.  而重载如果有非模版的,直接使用该版本
    重载会改变函数匹配顺序,因为增加了新函数
    几个函数都提供同样好的匹配的情况下,编译器会选择非板版本
    

    16.67

    定义特例化版本会影响 debug_rep 的函数匹配吗?如果不影响,为什么?
    
    不会改变,特例化模板函数不会重载函数,不会影响函数匹配顺序 也就是不产生新的函数类型
    
    > p262
    
    特例化是的本质是实例化一个模版,不影响函数匹配.  而重载如果有非模版的,直接使用该版本
    
    也就是他的匹配顺序是模版的顺序,模版之后下面来找具体的特例化(**可以理解为先匹配模版后才能匹配特例化**)
    
    而一个重载和一个模版是平等关系的
    ​```cpp
    重载的版本(包括模版)-------------模版
                                   |
                            |~~~~~~~~~~~~~~~|
                        特例化              通用的模版实现
    
    

  • 相关阅读:
    从搭eclipse环境到导入maven工程
    基于jquery的多选下拉列框再次更改样式和交互
    BootStrap的typeahead使用过程中遇到的问题
    Vue webapp项目通过HBulider打包原生APP
    微信相机
    前端小新手,记录项目中不懂的问题
    判断pdf、word文档、图片等文件类型(格式)、大小的简便方法
    JavaScript学习笔记(一)——Map、Set与iterable
    oracle nvl函数
    mybaits中主键自动生成并返回主键
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/12763083.html
Copyright © 2011-2022 走看看