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
- C++Primer第五版 第十六章习题答案(51~60)
- C++Primer第五版 第十六章习题答案(1~10)
- C++Primer第五版 第十六章习题答案(11~20)
- C++Primer第五版 第十六章习题答案(21~30)
- C++Primer第五版 第十六章习题答案(31~40)
- C++Primer第五版 第十六章习题答案(41~50)
- C++Primer第五版 第十六章习题答案(61~67)
- C++Primer(第五版) 习题答案
- C++Primer 中文版 第五版 第五章课后习题答案
- C++Primer第五版 第六章习题答案(51~56)
- C++Primer第五版 第七章习题答案(51~58)
- C++Primer第五版 第九章习题答案(51~52)
- C++Primer第五版 第十三章习题答案(51~58)
- C++Primer 第五版 (课本习题答案)
- C++Primer 中文版 第五版 第二章课后习题答案
- C++Primer 中文版 第五版 第三章课后习题答案
- C++Primer 中文版 第五版 第四章课后习题答案
- C++Primer 中文版 第五版 第六章课后习题答案
- V4L2 API及数据结构
- Android内存泄漏的检测APP
- windows下编译redis的32位程序
- 链表(篇2)删除右侧有更大值的节点
- I/O复用(一)
- C++Primer第五版 第十六章习题答案(51~60)
- rn 0.38 升到0.42 后 android出的问题 undefined is not function evaluating globalObject.hasownproperty('promi
- gcc -v以及-h处理
- iChart--组件定制
- unity standard shader 源码
- 并查集-4
- 面试谈薪要谈到点上,必须做到这“三不”
- Android对URl中的中文字符进行utf-8格式编码
- android app模拟操作的几种方式