C++Primer第五版 第十六章习题答案(51~60)

来源:互联网 发布:java大计算任务拆分 编辑:程序博客网 时间:2024/06/14 13:04

51:知识点1:可变函数模版就是指一个接受可变数目参数的模版函数或者模版类,可变数目的参数被称为参数包,分为两种:模版参数包,表示零个或多个模版参数,函数参数包,表示零个或多个函数参数

知识点2:C++11新标准才可用,利用一个省略号来表示一个模版参数或者函数参数为一个包

template<typename T, typename... U> void Foo(const T&, const U&...dest){//U表示一个模版参数包,dest表示一个函数参数包}

知识点3:当我们需要知道包中有多少元素时,我们可以使用sizeof...()运算符(注意有省略号),值求出参数的数目


答案:返回的是参数的个数


52:

Args.h

#ifndef ARGS_H#define ARGS_Htemplate<typename T, typename... U> void Foo(const T&, const U&...dest){//U表示一个模版参数包,dest表示一个函数参数包cout<<size...(U)<<endl;cout<<size...(dest)<<endl;}#endif ARGS_H

main.cpp

#include <iostream>#include <vector>#include <list>#include <string>#include "Args.h"using namespace std;int main(int argc,char** argv){int i = 2;string q = "54";double a = 3.14;Foo(i,q,45,a);Foo(i,q,45);Foo(i,q);Foo(i);cin.get();return 0;}


53:知识点1:使用参数初始化列表initializer list也可以定义一个可接受可变参数数目的函数,但是所有的实参都必须具有相同的类型(或者可转变为相同的类型)

知识点2:可变参数函数通常是递归的,第一步调用处理包中第一个实参,然后用剩余实参调用自身,所以我们在递归函数中,需要定义一个非可变参数版本版本的函数,以防无限递归

#include <iostream>  #include <string>  template<typename T>  std::ostream &print(std::ostream &os, const T &t)//非可变参数版本,递归的最后一次调用会选择该版本,因为比较特例化{      return os << t;  }  template<typename T,typename... Args>  std::ostream &print(std::ostream &os,const T &t,const Args&... args)  {      os << t << ", ";      return print(os, args...);  }    int main()  {      using namespace std;      int a = 1;      double d = 2.2;      string s = "c++ primer";        print(cout, 42) << endl;      print(cout, 42, d) << endl;      print(cout, 42, d, s, "hello", 'w') << endl;      system("pause");      return 0;  } 


54:缺少“<<”的定义


55:在其后定义,先前的版本找不到非可变参数版本的print函数,造成无限递归


56:知识点1:对于一个参数包,我们还可以对其进行参数扩展,即将一个包分解为其构成元素,我们通过在模式的右边放一个省略号...来出发扩展操作,见53题中print函数中的return语句

知识点2:我们还可以对作为参数的函数进行扩展,但注意省略号的位置,不是对函数参数的扩展

#include <iostream>  #include <string>  #include <sstream>    template <typename T> std::string debug_rep(const T& t);  template <typename T> std::string debug_rep(T* p);    std::string debug_rep(const std::string &s);  std::string debug_rep(char* p);  std::string debug_rep(const char *p);    template<typename T>  std::string debug_rep(const T &s)  {      std::ostringstream ret;      ret << s;      return ret.str();  }  template<typename T>  std::string debug_rep(T *p)  {      std::ostringstream ret;      std::cout << "point:" << s;      if (p)          ret << " " << debug_rep(*p);      else          ret << "point is NULL!";      return ret.str();  }  template<typename T>  std::ostream &print(std::ostream &os, const T &t)  {      return os << t;  }  template<typename T,typename... Args>  std::ostream &print(std::ostream &os, const T &t, const Args&... args)  {      os << t << ", ";      return print(os, args...);  }  std::string debug_rep(const std::string &s)  {      return '"' + s + '"';  }  std::string debug_rep(char *p)  {      return debug_rep(std::string(p));  }    std::string debug_rep(const char *p)  {      return debug_rep(std::string(p));  }  template<typename... Args>  std::ostream &errorMsg(std::ostream &os, const Args... args)  {      return print(os, debug_rep(args)...);  }    int main()  {      using namespace std;      string str = "c++";      errorMsg(cout, str, "primer", 4, 8.6, '5');        system("pause");      return 0;  }  


57:见53题知识点1


58:知识点:可变数目的参数被称为参数包

#include <iostream>  #include <string>  #include <memory> //allocator  #include <utility>    //move  #include <initializer_list>  #include <algorithm>  //for_each  class StrVec  {      std::allocator<std::string> alloc;//为所有StrVec对象分配内存用      void chk_n_alloc()      //如果剩余空间为0就分配新空间      {          if (size() == capacity())              reallocate();      }      std::pair<std::string *, std::string *> alloc_n_copy(const std::string *b, const std::string *e);//创建一个内容为b到e之间的元素的对象,并返回这个对象的一对头尾指针      void free();//释放所有alloc分配的所有内存      void reallocate();//移动当前对象的元素到2倍对象大小的新对象里      std::string *elements;      std::string *first_free;      std::string *cap;  public:      StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr){}      StrVec(std::initializer_list<std::string> il);      StrVec(const StrVec &s);      StrVec(StrVec &&s);      StrVec &operator=(StrVec &&s);      StrVec &operator=(const StrVec &s);        template<typename... Args>                //16.58      void emplace_back(Args&&... args)      {          chk_n_alloc();          alloc.construct(first_free++, std::forward<Args>(args)...);      }        bool operator==(const StrVec &s)//14.16      {          if (size() != s.size())              return false;          auto it = elements, its = s.elements;          while (it != first_free)          {              if (*it++ != *its++)                  return false;          }          return true;      }      bool operator!=(const StrVec &s)//14.16      {          return !(*this == s);      }      bool operator<(const StrVec &s)//14.18      {          if (size()>s.size())              return false;          else if (size() < s.size())              return true;          for (auto it = elements, its = s.elements; it != first_free; ++it, ++its)          {              if (*it == *its)                  continue;              else if (*it > *its)                  return false;              else                  return true;          }          return false;      }      bool operator>(const StrVec &s)//14.18      {          return !(*this < s) && *this != s;      }      bool operator<=(const StrVec &s)//14.18      {          return !(*this > s);      }      bool operator>=(const StrVec &s)//14.18      {          return !(*this < s);      }      StrVec &operator=(std::initializer_list<std::string> il)      {          auto nobj = alloc_n_copy(il.begin(), il.end());          free();          elements = nobj.first;          first_free = cap = nobj.second;          return *this;      }      std::string &operator[](std::size_t n)      {          return elements[n];      }      const std::string &operator[](std::size_t n)const      {          return elements[n];      }      ~StrVec();      void push_back(const std::string &s);//把string添加到尾后指针      size_t size()const      {          return first_free - elements;      }      size_t capacity()const      {          return cap - elements;      }      std::string *begin()const      {          return elements;      }      std::string *end()const      {          return first_free;      }  };  void StrVec::push_back(const std::string &s)  {      chk_n_alloc();//确保空间剩余      alloc.construct(first_free++, s);//在尾后构建一个s(s的拷贝构造函数构造),并把尾后指针first_free指向下一个  }  std::pair<std::string *, std::string *> StrVec::alloc_n_copy(const std::string *b, const std::string *e)  {      auto data = alloc.allocate(e-b);//分配并返回n个string对象的地址 string *      return{ data, std::uninitialized_copy(b, e, data) };//uninit_copy返回尾后指针string *      //把l~r之间的元素拷贝到data开始的地址,并返回data尾后,然后使用data(begin)和返回值(end)构建一个pair<string *,string *>  }  void StrVec::free()  {      if (elements)//如果不为空      {          for (auto p = first_free; p != elements;)              alloc.destroy(--p);//从最后一个元素开始向前摧毁,调用p的析构函数          //for_each(elements, first_free, [this](std::string *s){alloc.destroy(s); });//13.43          alloc.deallocate(elements, cap - first_free);//释放elements开始的n的string对象的内存      }  }  StrVec::StrVec(std::initializer_list<std::string> il)  {      auto newdata = alloc_n_copy(il.begin(), il.end());      elements = newdata.first;      first_free = cap = newdata.second;  }  StrVec::StrVec(const StrVec &s)  {      auto newdata = alloc_n_copy(s.begin(), s.end());//创建一个s的副本 值      elements = newdata.first;//把头指向新创建的副本的头      first_free = cap = newdata.second;//把尾后和内存尾指向副本的尾(以后调用会调用chk_n_alloc,不用担心剩余空间大小)  }  StrVec::StrVec(StrVec &&s) :elements(s.elements), first_free(s.first_free), cap(s.cap)  {      s.elements = s.first_free = s.cap = nullptr;  }  StrVec &StrVec::operator=(StrVec &&s)  {      if (this == &s)          return *this;      free();      elements = s.elements;      first_free = s.first_free;      cap = s.cap;      s.elements = s.first_free = s.cap = nullptr;      return *this;  }  StrVec::~StrVec()  {      free();//清理当前对象alloc分配的内存  }  StrVec &StrVec::operator=(const StrVec &s)  {      if (this == &s)          return *this;      auto data = alloc_n_copy(s.elements, s.first_free);      free();      elements = data.first;      first_free = cap = data.second;      return *this;  }  void StrVec::reallocate()  {      auto newcapacity = size() ? 2 * size() : 1; //当前空间的两倍大小      auto newdata = alloc.allocate(newcapacity); //分配并返回newcapacity个string对象大小的空间      auto dest = newdata;      auto elem = elements;//指向当前对象的头      for (size_t i = 0; i != size(); ++i)      {          alloc.construct(dest++, std::move(*elem++));//move会让elem指向的string对象放弃自己的内存管理权并返回,然后construct使用string的移动构造函数构建dest指向的地址      }                                               //接受dest会指向newdata的尾后      free();             //移动完后释放当前对象指向的内存      elements = newdata; //指向新头      first_free = dest;  //指向新尾后           cap = elements + newcapacity;   //指向内存尾  }


59:s作为参数被转发


60:可接受可变参数模板,转发其参数初始化一个内存于内存空间,返回一个shared_ptr


1 0
原创粉丝点击