• C++Primer 16.1定义模板 习题总结


    目录

    16.1.1 函数模板

    练习16.4 模拟实现find标准库函数

    练习16.5 print函数,打印任意元素类型,任意大小的数组。

    练习16.6 模拟接收一个数组实参的begin end标准库函数的实现。

    16.1.2 类模板 

    Blob 类模板和BlobPtr类模板实现

    练习16.14 Screen类模板,用非类型模板参数定义Screen的高和宽

    16.1.3 模板参数 

     默认模板实参: compare函数的进一步定义。

     练习 16.19 16.20

    16.1.4 成员模板

    练习16.21  DebugDelete类实现,普通类的成员模板。 

     16.1.5 控制实例化

    16.1.6  效率与灵活性

    练习16.28


    16.1.1 函数模板

    1. template <typename T> // 其实就是代表一个类型而已,也没啥。
    2. int compare(const T &v1, const T &v2){
    3. if(v1 < v2) return -1;
    4. if(v2 < v1) return 1;
    5. return 0;
    6. }

    模板实现compare函数,用于任意两种相同类型的比较,前提是,此类型支持<运算符。

    练习16.4 模拟实现find标准库函数

    1. template <typename T1, typename T2>
    2. T1 my_find(const T1& beg,const T1& end,const T2& value){
    3. for(auto i = beg; i != end; ++i){
    4. if(*i == value)
    5. return i;
    6. }
    7. return end;
    8. }

    练习16.5 print函数,打印任意元素类型,任意大小的数组。

    1. template <typename T, unsigned int sz> // sz是unsigned类型常量。
    2. void print(const T (&arr)[sz]){
    3. for(int i = 0; i != sz; ++i){
    4. cout<<arr[i]<<" ";
    5. }
    6. cout<<endl;
    7. }
    8. void test_16_5(){
    9. int arr1[5] = {1,2,3,4,5};
    10. print(arr1);
    11. string arr2[3] = {"aaa","bbb","ccc"};
    12. print(arr2);
    13. }

    这里用到了非类型模板参数,其中的unsigned int sz就是一个非类型模板参数,可用于模板中需要常量的地方,根据传来的函数实参进行推断此非类型模板参数的模板实参。比如 第一个print中sz = 5,第二个print中sz = 3

    练习16.6 模拟接收一个数组实参的begin end标准库函数的实现。

    1. template <typename T, size_t sz>
    2. T* my_begin(T (&arr)[sz]){
    3. return &arr[0];
    4. }
    5. template <typename T, size_t sz>
    6. T* my_end(T (&arr)[sz]){
    7. return &arr[0] + sz;
    8. }
    9. template <typename T, size_t sz>
    10. const T* my_cbegin(const T (&arr)[sz]){
    11. const T* ret = &arr[0];
    12. return ret;
    13. }
    14. template <typename T, size_t sz>
    15. const T* my_cend(const T (&arr)[sz]){
    16. const T* ret = &arr[0] + sz;
    17. return ret;
    18. }

    16.1.2 类模板 

    Blob 类模板和BlobPtr类模板实现

    1. template <typename> class BlobPtr;
    2. template <typename> class Blob;
    3. template <typename T>
    4. bool operator==(const Blob<T>&, const Blob<T>&);
    5. template <typename T>
    6. class Blob{
    7. friend class BlobPtr<T>;
    8. friend bool operator==<T> (const Blob<T>&, const Blob<T>&);
    9. public:
    10. using size_type = typename vector<T>::size_type;
    11. template <typename It> Blob(It t1, It t2);
    12. // : data(make_shared<vector<T>>(t1,t2)) {}
    13. Blob(): data(make_shared<vector<T>>()) {}
    14. Blob(initializer_list<T> il):data(make_shared<vector<T>>(il)) {}
    15. size_type size()const { return data->size(); }
    16. bool empty()const { return data->empty(); }
    17. void push_back(const T& ele) { data->push_back(ele); }
    18. void push_back(T &&ele) { data->push_back(std::move(ele)); }
    19. void pop_back();
    20. T& back();
    21. const T& back()const;
    22. T& operator[](size_type i);
    23. const T& operator[](size_type i)const;
    24. private:
    25. shared_ptr<vector<T>> data;
    26. void check(size_type i, const string& msg)const;
    27. };
    28. template <typename T> template <typename It> Blob<T>::Blob(It t1, It t2):data(make_shared<vector<T>>(t1,t2)) {}
    29. template <typename T> void Blob<T>::check(size_type i, const string& msg)const{
    30. if(i>=data->size())
    31. throw out_of_range(msg);
    32. }
    33. template <typename T> void Blob<T>::pop_back(){
    34. check(0,"pop_back on empty Blob");
    35. data->pop_back();
    36. }
    37. template <typename T>
    38. T& Blob<T>::back(){
    39. check(0,"back on empty Blob");
    40. return data->back();
    41. }
    42. template <typename T>
    43. const T& Blob<T>::back()const{
    44. check(0,"beck on empty Blob");
    45. return data->back();
    46. }
    47. template <typename T>
    48. T& Blob<T>::operator[](size_type i){
    49. check(i,"subscript out of range");
    50. return (*data)[i];
    51. }
    52. template <typename T>
    53. const T& Blob<T>::operator[](size_type i)const{
    54. check(i,"subscript out of range");
    55. return (*data)[i];
    56. }
    57. template <typename T>
    58. class BlobPtr
    59. {
    60. public:
    61. BlobPtr(): curr(0) {}
    62. BlobPtr(Blob<T>& a, size_t sz = 0): wptr(a.data), curr(sz) {} // 仅一个Blob对象作为参数,curr默认为0;
    63. T& operator*() const{
    64. auto p = check(curr, "dereference past end");
    65. return (*p)[curr];
    66. }
    67. // prefix
    68. BlobPtr& operator++();
    69. BlobPtr& operator--();
    70. // postfix
    71. BlobPtr operator ++(int);
    72. BlobPtr operator --(int);
    73. private:
    74. // returns a shared_ptr to the vector if the check succeeds;
    75. shared_ptr<vector<T>> check(size_t, const string& msg)const;
    76. weak_ptr<vector<T>> wptr;
    77. size_t curr;
    78. };
    79. template <typename T>
    80. shared_ptr<vector<T>> BlobPtr<T>::check(size_t index, const string& msg)const{
    81. auto p = wptr.lock();
    82. if (p) {
    83. if (p->size() > index) {
    84. return p;
    85. } else {
    86. throw std::out_of_range(msg);
    87. }
    88. } else {
    89. throw "unbind BlobPtr";
    90. }
    91. }
    92. // prefix ++
    93. template <typename T> BlobPtr<T>& BlobPtr<T>::operator++(){
    94. check(curr, "increment past end of StrBlob");
    95. ++curr;
    96. return *this;
    97. }
    98. template <typename T> BlobPtr<T>& BlobPtr<T>::operator--(){
    99. --curr;
    100. check(-1, "decrease index pass the beg");
    101. return *this;
    102. }
    103. template <typename T> BlobPtr<T> BlobPtr<T>::operator++(int){
    104. BlobPtr ret = *this;
    105. ++*this; // 利用前置加加检验递增是否合法
    106. return ret;
    107. }
    108. template <typename T> BlobPtr<T> BlobPtr<T>::operator--(int){
    109. BlobPtr ret = *this;
    110. --*this;
    111. return ret;
    112. }

    Blob类模板,就是很简单的一个类模板的练习,模拟vector,根据模板实参确定保存的元素类型。剩余的就是一些定义,声明的规则了。还有,比如使用类模板的类型成员,需要声明typename,类模板的模板成员,如Blob类的接收两个迭代器参数的构造函数,就是一个函数模板,定义时,类模板的模板参数列表和函数模板的模板参数列表都需要声明。以及BlobPtr类定义时,在参数的作用域范围内,返回值BlobPtr可以省略模板实参,这都是一些小的规则而已。

    练习16.14 Screen类模板,用非类型模板参数定义Screen的高和宽

    1. #ifndef C__PRIMER_SCREEN_16_14_H
    2. #define C__PRIMER_SCREEN_16_14_H
    3. #include<iostream>
    4. #include<string>
    5. using namespace std;
    6. template<int H,int W> class Screen; // 声明这个,下面的<<>>声明才可以
    7. template<int H,int W> ostream& operator<<(ostream& os, const Screen<H,W>&);
    8. template<int H,int W> istream& operator>>(istream& is, Screen<H,W>&);
    9. template <int H, int W>
    10. class Screen{
    11. friend ostream& operator<< <H,W>(ostream&,const Screen<H,W>&);
    12. friend istream& operator>> <H,W>(istream&,Screen<H,W>&);
    13. public:
    14. Screen() : contents(W*H,' ') {}
    15. Screen(char c):contents(W*H, c) {}
    16. char get()const { return contents[cursor]; } // 隐式内联
    17. inline char get(int, int)const; // 显式内联
    18. Screen& clear(char c = bkground);
    19. private:
    20. static const char bkground = ' ';
    21. public:
    22. Screen& move(int,int);
    23. Screen& set(char);
    24. Screen& set(int,int,char);
    25. Screen& display(ostream& os)
    26. { do_display(os); return *this; }
    27. const Screen& display(ostream& os)const
    28. { do_display(os); return *this;}
    29. private:
    30. //实际完成显式的函数
    31. void do_display(ostream& os)const {os<<contents;}
    32. int cursor = 0;
    33. string contents;
    34. };
    35. template <int H, int W> inline char Screen<H,W>::get(int r,int c)const{
    36. return contents[r*W+c];
    37. }
    38. template<int H,int W> Screen<H,W>& Screen<H,W>::clear(char c){
    39. contents = string(H*W,c);
    40. return *this;
    41. }
    42. template <int H,int W> inline Screen<H,W>& Screen<H,W>::move(int r,int c){
    43. cursor = r*W+c;
    44. return *this;
    45. }
    46. template<int H, int W>
    47. Screen<H,W>& Screen<H, W>::set(char c){
    48. contents[cursor] = c;
    49. return *this;
    50. }
    51. template<int H,int W>
    52. Screen<H,W>& Screen<H,W>::set(int r,int col,char ch){
    53. contents[r*W+col] = ch;
    54. return *this;
    55. }
    56. template<int H,int W> ostream& operator<<(ostream& os, const Screen<H,W>& s){
    57. os<<s.contents;
    58. return os;
    59. }
    60. template<int H,int W> istream& operator>>(istream& is, Screen<H,W>& s){
    61. string t;
    62. cin >> t;
    63. s.contents = t.substr(0,H*W);
    64. return is;
    65. }
    66. #endif //C__PRIMER_SCREEN_16_14_H

     用非类型模板实参确定Screen的高和宽,而不是之前的把高和宽定义为私有数据成员。也是一个练习而已。注意<< >> 运算符重载函数,仍然需要模板,且友元声明时,   

    friend ostream& operator<< <H,W>(ostream&,const Screen<H,W>&);
    friend istream& operator>> <H,W>(istream&,Screen<H,W>&);

    需要加上<H,W>。还有类模板的声明,以及函数声明。

    16.1.3 模板参数 

     默认模板实参: compare函数的进一步定义。

    1. template < typename T, typename F = less<T> >
    2. int compare(const T& v1, const T& v2, F f = F()){
    3. if(f(v1,v2))
    4. return -1;
    5. if(f(v2,v1))
    6. return 1;
    7. return 0;
    8. }

     练习 16.19 16.20

    1. // 16.19
    2. template <typename T>
    3. void print(const T& v){
    4. for(typename T::size_type sz = 0; sz!=v.size();++sz) {
    5. cout << v[sz] << " ";
    6. }
    7. }
    8. template <typename T>
    9. void print_2(const T& v){
    10. for(auto i = v.begin(); i != v.end(); ++i){
    11. cout<<*i<<" ";
    12. }
    13. cout<<endl;
    14. }

     使用类的类型成员

    16.1.4 成员模板

    练习16.21  DebugDelete类实现,普通类的成员模板。 

    1. // 16.1.4
    2. class DebugDelete
    3. {
    4. public:
    5. explicit DebugDelete(ostream& o = cerr): os(o) {}
    6. template <typename T> void operator() (T* p)const { cout<<"deleting unique_ptr"<<endl; delete p;}
    7. private:
    8. ostream& os;
    9. };
    10. void test_16_21(){
    11. int* pi = new int(10);
    12. DebugDelete d;
    13. d(pi);
    14. string* ps = new string("hahaha");
    15. DebugDelete()(ps);
    16. }

     16.1.5 控制实例化

     ........

    16.1.6  效率与灵活性

    练习16.28  shared_ptr unique_ptr简单实现

    1. // 16.1.6 效率与灵活性 test16_28
    2. template <typename T>
    3. class Shared_p{
    4. public:
    5. Shared_p():p(nullptr), use(nullptr){}
    6. // shared_p<int> p(new int(1));
    7. explicit Shared_p(T* pt):p(pt), use(new size_t(1)) {}
    8. Shared_p(const Shared_p& sp): p(sp.p),use(sp.use){
    9. if(use) ++*use;
    10. }
    11. Shared_p& operator=(const Shared_p& sp);
    12. ~Shared_p();
    13. T& operator*() { return *p; }
    14. T& operator*()const { return *p; }
    15. private:
    16. T* p;
    17. size_t* use;
    18. };
    19. template<typename T> Shared_p<T>& Shared_p<T>::operator=(const Shared_p& rhs){
    20. if(rhs.use)
    21. ++*use;
    22. if(use && --*use == 0) {
    23. delete p;
    24. delete use;
    25. }
    26. p = rhs.p;
    27. use = rhs.use;
    28. return *this;
    29. }
    30. template<typename T> Shared_p<T>::~Shared_p(){
    31. if(use && --*use == 0){
    32. delete use;
    33. delete p;
    34. }
    35. }
    36. template <typename T, class... Args>
    37. Shared_p<T> make_shared(Args&&... args){
    38. return Shared_p<T>(new T(forward<Args>(args)...));
    39. }
    40. template <typename T>
    41. class UP
    42. {
    43. public:
    44. UP():p(nullptr){}
    45. explicit UP(T* pt):p(pt){}
    46. UP(const UP&) = delete;
    47. UP& operator=(const UP&)=delete;
    48. ~UP(){
    49. if(p)
    50. delete p;
    51. }
    52. T* release(){
    53. T* ret = p;
    54. p = nullptr;
    55. return ret;
    56. }
    57. T* reset(T* new_p = nullptr){
    58. if(p)
    59. delete p;
    60. p = new_p;
    61. }
    62. T& operator*() { return *p; }
    63. T* operator*()const { return *p; }
    64. private:
    65. T* p;
    66. };

  • 相关阅读:
    Linux 目录结构介绍
    Python爬虫入狱小技巧
    基于PHP+MySQL菜品食谱美食网站的设计与实现
    nacos配置中心
    用路由器远程维护三菱PLC操作指南
    每日一道算法题
    初识设计模式之单例模式
    Spring Boot之容器功能
    科技云报道:Citrix正式退出中国市场!国产们谁能真正顶上?
    Unity之Hololens开发如何实现UI交互
  • 原文地址:https://blog.csdn.net/i777777777777777/article/details/125404423