c++primer第五版第十六章练习

16.1

根据模板参数的类型实例化出一个该类型的函数

16.2

#include <iostream>
#include <string>
#include <functional> //less
//#include "../../7.21/7.21/标头.h"
template<typename T>
int compare(const T &a, const T &b) {
	if (std::less<T>()(a, b))return 1;
	if (std::less<T>()(b, a))return -1;
	return 0;
}

int main()
{
	using namespace std;
	string a, b;
	//Sales_data b1("a"), b2("b");
	cin >> a >> b;
	if (compare(a, b) > 0)cout << a << "<" << b << endl;
	if (compare(a, b) < 0)cout << a << ">" << b << endl;
	if (!compare(a, b))cout << a << "=" << b << endl;
	//cout << compare(b1, b2);
	system("pause");
	return 0;
}

16.3

错误:Sales_data类型未定义运算符"<"

16.4

#include <iostream>
#include <vector>
#include <list>
#include <string>
template<typename Iterator, typename Value>
auto find(Iterator first, Iterator last, Value const& value)
{
	for (; first != last && *first != value; ++first);
	return first;
}
int main()
{
	std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	auto is_in_vector = v.cend() != ::find(v.cbegin(), v.cend(), 8);
	std::cout << (is_in_vector ? "找到\n": "没找到\n");

	std::list<std::string> l = { "aa", "bb", "cc", "dd", "ee", "ff", "gg" };
	auto is_in_list = l.cend() != ::find(l.cbegin(), l.cend(), "ab");
	std::cout << (is_in_list ? "找到\n" : "没找到\n");
	system("pause");
	return 0;
}

16.5

#include <iostream>
//template<typename T>
//void prin(const T &a)
//{
//	auto b = std::begin(a), e = std::end(a);
//	for (; b != e; ++b)
//		std::cout << *b << " ";
//}
//int main()
//{
//	using namespace std;
//	int a[] = { 1,2,3,4,5,6,9,8,7 };
//	string str = "primer 5";
//	prin(a);
//	prin(str);
//	system("pause");
//	return 0;
//}

template<class T, unsigned N>
void prin(T(&ar)[N])
{
	for (int i = 0; i < N; ++i)
		std::cout << ar[i];
}
int main()
{
	using namespace std;
	int ar[9] = { 4,0,8,6,8,6,4,7,7 };
	char str[] = "helloworld!";
	prin(ar);
	prin(str);
	prin("c++ primer");
	system("pause");
	return 0;
}

16.6

#include <iostream>

template<typename T>
void print(const T &ar) {
	auto beg = ::begin(ar), end = ::end(ar);
	while (beg != end) {
		std::cout << *beg++ << " ";
	}
}
template<class T>
auto begin(const T &ar)
{
	return ar;
}
template<class T>
auto end(const T &ar)
{
	return ar + (sizeof ar) / sizeof(*ar);	//整个数组的大小除以单个元素的大小得到数量,指向数组之后
}
int main()
{
	using namespace std;
	int l[] = { 2,0,1,6,0,1,0,6 };
	print("c++ primer");
	print(l);
	system("pause");
	return 0;
}

16.7

#include <iostream>
template<class T>
constexpr size_t sizear(const T &ar) {
	return sizeof ar;
}
int main()
{
	int ar[] = { 1,2,3,4,5,6,7,8 };
	int *p = ar;
	std::cout << sizear(ar) << std::endl;
	system("pause");
	return 0;
}

16.8

因为所有的标准库容器都有提供==与!=的运算符,而不一定有提供<运算符,所以使用!=能在所有的标准库容器上工作

16.9

函数模板就是一个公式,可以用来生成特定类型的函数版本。

16.10

生成一个特定类型的类,该类中特定类型被替换

16.11

//Blob.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>	//shared_ptr
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:
	friend class BlobPtr<T>;
	friend bool operator==<T>(const Blob &l, const Blob &r);
	typedef T value_type;
	typedef typename std::vector<T>::size_type size_type;	//把size_type视为类型名,忽略vector里同名的(如果有)静态变量
	Blob();
	Blob(std::initializer_list<T> il);

	size_type size()const {						//返回元素数量
		return data->size();
	}
	bool empty()const {							//是否为空
		return data->empty();
	}
	void push_back(const T &t) {				//添加元素到末尾
		data->push_back(t);
	}
	void push_back(T &&t) {
		data->push_back(std::move(t));
	}
	void pop_back();							//弹出末尾元素
	T &back();									//返回末尾元素的引用
	T &operator[](size_type i);					//返回第i个元素的引用
private:
	std::shared_ptr<std::vector<T>> data;
	void check(size_type i, const std::string &msg)const;
};

template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
	if (i >= data->size())
		throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
	check(0, "back on empty Blob");
	return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
	check(i, "subscript out range");
	return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
	check(0, "pop_back on empty Blob");
	data->pop_back();
}
template<typename T>
Blob<T>::Blob():data(std::make_shared<std::vector<T>>()){
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>> (il)) {
}

template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
	if (l.data != r.data)
		return false;
	return true;
}
//BlobPtr.h
#pragma once
#include "Blob.h"
template<typename T>
class BlobPtr {
public:
	BlobPtr();
	BlobPtr(Blob<T> &a, size_t sz = 0);
	T &operator*()const;
	BlobPtr &operator++();
	BlobPtr &operator--();
private:
	std::shared_ptr<std::vector<T>> check(std::size_t i, const std::string &s)const;
	std::weak_ptr<std::vector<T>> wptr;
	std::size_t curr;
};
template<typename T>
BlobPtr<T>::BlobPtr() :curr(0) {}

template<typename T>
BlobPtr<T>::BlobPtr(Blob<T> &a, size_t sz /* = 0 */) : wptr(a.data), curr(sz) {}

template<typename T>
T &BlobPtr<T>::operator*()const {
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

template<typename T>
BlobPtr<T> &BlobPtr<T>::operator++() {
	++curr;
	check(curr, "++obj error");
	return *this;
}

template<typename T>
BlobPtr<T> &BlobPtr<T>::operator--() {
	--curr;
	if (curr < 0)
		throw std::out_of_range("--obj error");
	return *this;
}

template<typename T>
std::shared_ptr<std::vector<T>> BlobPtr<T>::check(std::size_t i, const std::string &s)const {
	auto ret = wptr.lock();									//确认未被释放内存
	if (!ret)
		throw std::out_of_range("unbound BlobPtr");
	if (i >= ret->size())
		throw std::out_of_range(s);
	return ret;
}

16.13

1 VS 1

让不同类型的类模板相等无意义

16.14,16.15

#pragma once
#include <string>
#include <iostream>
struct xyc {
	int x=0;
	int y=0;
	char c=' ';
};
template<unsigned N,unsigned M>
class Screen
{
	unsigned cursor = 0;
	unsigned  width = N, height = M;
	std::string contents;
public:
	Screen() = default;
	Screen(char c) :contents(N*M, c) {}
	char get()const { return contents[cursor]; }
	Screen set(xyc c) {
		cursor = --c.x*width + --c.y;
		contents[cursor] = c.c;
		return *this;
	}
	template<unsigned NN,unsigned MM>
	friend std::ostream &operator<<(std::ostream &os, const Screen<NN, MM> &s);
	template<unsigned NN, unsigned MM>
	friend std::istream &operator>>(std::istream &is, Screen<NN, MM> &s);
};

template<unsigned NN, unsigned MM>
std::ostream &operator<<(std::ostream &os, const Screen<NN, MM> &s)
{
	for (unsigned i = 0; i < s.width; ++i)
	{
		for (unsigned j = 0; j < s.height; ++j)
			putchar(s.contents[i*s.width + j]);
		putchar('\n');
	}
	return os;
}
template<unsigned NN, unsigned MM>
std::istream &operator>>(std::istream &is, Screen<NN, MM> &s)
{
	xyc c;
	is >> c;
	s.set(c);
	return is;
}
#include "标头.h"
std::istream &operator>>(std::istream &is, xyc &c) {
	is >> c.x;
	is >> c.y;
	is >> c.c;
	return is;
}
int main()
{
	using namespace std;
	Screen<6, 6> scr('-');
	cout << scr;
	cin >> scr;
	cout << scr;
	system("pause");
	return 0;
}

16.16

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

int main()
{
	using namespace std;

	StrVec<char> str{ 'c','l','a','n','n','a','d' };
	cout << str;

	system("pause");
	return 0;
}

16.17

template<class T,typename T>在声明模板时没有区别,但是在制定为类型而不是静态值时就必须用typename: typename T::size_type func(); 这里的size_type是类型而不是值。

16.18

1、错误,不能连续声明模板参数             改为:template<typename T,typename U,typename V> void f1(T,U,V);

b、错误,模板参数名不能作为变量名     改为:template<typename T> T f2(T &);

c、错误,内联声明位置错误                      改为:template<typename T> inline T foo(T,unsigned int *);

d、错误,缺少返回类型                              改为:template<typename> T f4(T,T);

e、错误,模板参数将覆盖外层的Ctype   改为:typedef char C;或者是template<typename C> C f5(C a);

16.19

#pragma once
#include <iostream>
template<typename T>
void prin(T &s, std::ostream &os)
{
	typename T::size_type n=0,size = s.size();
	auto iter = s.begin();
	for (; n < size; ++n)
	{
		os << *iter++;
	}
}
#include "标头.h"
#include <vector>
int main()
{
	using namespace std;
	vector<char> str = { '1','2','3','4','5','6','7','8','9','0' };
	prin(str, cout);
	system("pause");
	return 0;
}

16.20

#pragma once
#include <iostream>
template<typename T>
void prin(T &s, std::ostream &os)
{
	for (auto beg = s.begin(); beg != s.end(); ++beg)
	{
		os << *beg;
	}
}
#include "标头.h"
#include <vector>
#include <list>
int main()
{
	using namespace std;
	vector<char> str = { '1','2','3','4','5','6','7','8','9','0' };
	list<int> lint = { 1,2,3,4,5,6,7,8,9 };
	prin(str, cout);
	prin(lint,cout);
	system("pause");
	return 0;
}

16.21

#pragma once
#include <iostream>
class DebugDelete
{
	std::ostream &os;
public:
	DebugDelete(std::ostream &s = std::cerr) :os(s) {}
	template<class T>
	void operator()(T *p) {
		os << "delete obj!!!" << std::endl;
		delete p;
	}
};

16.22

#ifndef HEAD_H_
#define HEAD_H_
#include "DebugDelete.h"
#include <iostream>
#include <fstream>	//ifstream
#include <string>
#include <vector>
#include <sstream>	//istringstream
#include <map>
#include <set>
#include <memory>	//shared_ptr
class QueryResult;
using line_no = std::vector < std::string > ::size_type;
class TextQuery
{

	std::shared_ptr<std::vector<std::string>> file;					//保存整个文件内容,按行分
	std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;	//每个单词对应行号
public:

	TextQuery(std::ifstream &is);
	QueryResult query(const std::string &s)const;					//返回QR,单词、行号set,还有关联到文件内容
};
class QueryResult
{
	friend std::ostream &print(std::ostream &os, const QueryResult &qr);
	std::string sought;
	std::shared_ptr<std::set<line_no>> lines;						//记录出现的行号
	std::shared_ptr<std::vector<std::string>> file;					//关联到文件内容
public:
	QueryResult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>> f) :sought(s), lines(p), file(f){}
};
TextQuery::TextQuery(std::ifstream &is) :file(new std::vector<std::string>(),DebugDelete(std::cout))	//为智能指针file分配空间    16.22
{
	std::string text;
	while (getline(is, text))
	{
		file->push_back(text);
		int n = file->size() - 1;
		std::istringstream line(text);
		std::string word;
		while (line >> word)
		{
			auto &lines = wm[word];						//如果word在wm中第一次出现,那么对应的set就未分配内存,所以为空
			if (!lines)										//如果第一次出现
				lines.reset(new std::set<line_no>());
			lines->insert(n);
		}
	}
}
QueryResult TextQuery::query(const std::string &s)const
{
	static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>());	//当没找到单词时返回	内存常驻
	auto loc = wm.find(s);
	if (loc == wm.end())
		return QueryResult(s, nodata, file);
	else
		return QueryResult(s, loc->second, file);
}
std::ostream &print(std::ostream &os, const QueryResult &qr)
{
	os << qr.sought << " occurs " << qr.lines->size() << " " << (qr.lines->size() > 1 ? "times" : "time") << std::endl;
	for (auto x : *qr.lines)			//*(qr.file->begin()+x)
		os << "\t(line " << x + 1 << ") " << (*qr.file)[x] << std::endl;	//file返回一个指向vec的智能指针,解引用后得到vector 然后使用下标运算符
	return os;
}
#endif

16.23

在对象介绍声明周期时掉用

16.24

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>	//shared_ptr
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:
	friend class BlobPtr<T>;
	friend bool operator==<T>(const Blob &l, const Blob &r);
	typedef T value_type;
	typedef typename std::vector<T>::size_type size_type;	//把size_type视为类型名,忽略vector里同名的(如果有)静态变量
	Blob();
	Blob(std::initializer_list<T> il);
	template<class U>
	Blob(U b, U e);
	size_type size()const {						//返回元素数量
		return data->size();
	}
	bool empty()const {							//是否为空
		return data->empty();
	}
	void push_back(const T &t) {				//添加元素到末尾
		data->push_back(t);
	}
	void push_back(T &&t) {
		data->push_back(std::move(t));
	}
	void pop_back();							//弹出末尾元素
	T &back();									//返回末尾元素的引用
	T &operator[](size_type i);					//返回第i个元素的引用
private:
	std::shared_ptr<std::vector<T>> data;
	void check(size_type i, const std::string &msg)const;
};

template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
	if (i >= data->size())
		throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
	check(0, "back on empty Blob");
	return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
	check(i, "subscript out range");
	return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
	check(0, "pop_back on empty Blob");
	data->pop_back();
}
template<typename T>
Blob<T>::Blob():data(std::make_shared<std::vector<T>>()){
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {
}

template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
	if (l.data != r.data)
		return false;
	return true;
}

template<class T>
template<class U>
Blob<T>::Blob(U b, U e) :data(std::make_shared < std::vector<T>>(b, e)) {}
#include "Blob.h"
int main()
{
	using namespace std;
	int vi[] = { 1,2,3,4,5,6 };
	Blob<int> b(begin(vi), end(vi));
	for (typename Blob<int>::size_type i = 0; i != b.size(); ++i)
	{
		cout << b[i];
	}
	system("pause");
	return 0;
}

16.25

extern template class vector<string>;//声明一个实例化,但是该实例化的定义不一定在本模块,提示编译器可以在其他模块查找

template clss vector<Sales_data>;//定义一个实例化,让编译器生成一个实例

16.26

不可以,因为下面的就会报错:

vector<NoDefault> vN(10);//error,没有NoDefault类没有默认构造函数

16.27

a:没有实例化,只有在有数据时才会实例化

b:没有实例化,引用并不会实例化,因为没有数值存在

c:实例化出一个Stack<int>的实例

d:没有实例化,指针不会实例化,他包含的是地址

e:实例化出一个Stack<char>的实例,因为函数接收到数据,而且是按值传递

f:实例化出一个Stack<string>的实例,

16.28

//DebugDelete.h
#pragma once
#include <iostream>
class DebugDelete
{
public:
	DebugDelete(std::ostream& s = std::cerr) : os(s) { }
	template<typename T>
	void operator() (T* p) const
	{
		os << "deleting ptr" << std::endl;
		delete p;
	}

private:
	std::ostream& os;
};
#pragma once	//shared_p.h
#include <functional>
#include "DebugDelete.h"
#include <memory>
template<typename T>class shared_p;

class SharedPtrControlBlock								//保存引用数所使用
{
	template<typename T>friend class shared_p;
	int _count;
	SharedPtrControlBlock() :_count(1){}
};

template<typename T>
class shared_p
{
	T *_ptr;
	SharedPtrControlBlock *control_block;
	std::function<void(T*)> deleter{ DebugDelete() };
	template<typename U>
	void Initialize(const shared_p<U> &r)
	{
		if (r.control_block != nullptr)
		{
			AtomicIncrement(&r.control_block->_count);
			_ptr = r._ptr;
			control_block = r.control_block;
			deleter = r.deleter;
		}
	}
public:
	explicit shared_p(T *ptr = nullptr, std::function<void(T*)> f = DebugDelete())
		:_ptr(ptr),
		control_block(_ptr != nullptr ? new SharedPtrControlBlock : nullptr),
		deleter(f) {}

	shared_p(const shared_p &p)
	{
		Initialize(p);
	}

	shared_p &operator=(shared_p &p)
	{
		if (_ptr != p._ptr)
		{
			shared_p temp(p);
			swap(temp);
		}
		return *this;
	}

	shared_p(std::shared_ptr<T> &&sp)
	{
		if (sp.unique())
		{
			/*shared_p<T> temp =shared_p(new T(*sp));
			_ptr = temp._ptr;
			control_block = temp.control_block;*/
			*this = shared_p(new T(*sp));

		}
		else
			throw std::runtime_error("unique error!!");
	}

	template<typename U>
	friend std::ostream &operator<<(std::ostream &os, const shared_p<U> &s);

	~shared_p()
	{
		if (_ptr != nullptr)
		{
			if (AtomicDecrement(&control_block->_count) == 0)
			{
				deleter(_ptr);
				delete control_block;
			}
		}
	}

	int AtomicDecrement(int *count)
	{
		return --*count;
	}

	int AtomicIncrement(int *count)
	{
		return ++*count;
	}

	void reset(T *p = nullptr,std::function<void(T*)> del=DebugDelete())
	{
		if (p != _ptr)
		{
			shared_p temp(p);
			temp->swap(*this);
			deleter = del;
		}
	}

	void swap(shared_p &r)
	{
		std::swap(_ptr, r._ptr);
		std::swap(control_block, r.control_block);
		std::swap(deleter, r.deleter);
	}

	T *get()const
	{
		return _ptr;
	}

	T &operator*()const
	{
		return *_ptr;
	}

	auto &operator[](int n)
	{
		return (*_ptr)[n];
	}

	T *operator->()const
	{
		return _ptr;
	}

	int use_count()const	//返回引用数
	{
		return control_block ? control_block->_count : 1;
	}

	bool unique()const		//是否单一占用 引用==1
	{
		return use_count() == 1;
	}
};

template<class T>
std::ostream &operator<<(std::ostream &os, const shared_p<T> &s)
{
	os << *s._ptr;
	return os;
}
#pragma once	//unique_p.h
#include <functional>
#include "DebugDelete.h"
template<typename T>
class unique_p
{
	T *_ptr;
	std::function<void(T*)> deleter{ DebugDelete() };
public:
	explicit unique_p(T *ptr = nullptr, std::function<void(T*)> del = DebugDelete()) :_ptr(ptr), deleter(del) {}

	unique_p(unique_p &u) :_ptr(u._ptr), deleter(u.deleter)
	{
		u._ptr = nullptr;
		u.deleter = nullptr;
	}

	unique_p(unique_p &&u) :_ptr(u._ptr), deleter(u.deleter)
	{
		u._ptr = nullptr;
		u.deleter = nullptr;
	}

	unique_p &operator=(unique_p &u)
	{
		_ptr = (u._ptr);
		deleter = u.deleter;
		u.deleter = nullptr;
		u._ptr = nullptr;
	}

	unique_p &operator=(unique_p &&u)
	{
		_ptr = (u._ptr);
		deleter = u.deleter;
		u.deleter = nullptr;
		u._ptr = nullptr;
	}

	template<typename U>
	friend std::ostream &operator<<(std::ostream &os, const unique_p &u);

	~unique_p()
	{
		delete _ptr;
	}

	void swap(unique_p &u)
	{
		std::swap(_ptr, u._ptr);
		std::swap(deleter, u.deleter);
	}

	void reset(T *p = nullptr, std::function<void(T*)> del = DebugDelete())
	{
		if (p != _ptr)
		{
			unique_p<T> temp(p);
			temp.swap(*this);
		}
	}

	T *get()const
	{
		return _ptr;
	}

	T &operator*()const
	{
		return *_ptr;
	}

	auto &operator[](int n)
	{
		return (*_ptr)[n];
	}

	T *operator->()const
	{
		return _ptr;
	}
};

template<typename T>
std::ostream &operator<<(std::ostream &os, const unique_p<T> &u)
{
	os << *_ptr;
	return os;
}
#include <iostream>
#include "shared_p.h"
#include "unique_p.h"
#include <vector>
#include <string>
#include <memory>

int main()
{
	using namespace std;
	shared_p<vector<char>> sv(new vector<char>);
	char a;
	while ((a = getchar()) != 'q')
		sv->push_back(a);
	for (auto &x : *sv)
		cout << x;
	unique_p<int> ui(new int(4096));
	cout << *ui;
	unique_p<int> uii(ui);
	cout << *uii;
	system("pause");
	cout << *ui;	//出错,空指针
	system("pause");
	return 0;
}

16.29、16.30

#pragma once	//shared_p.h
#include "shared_p.h"
#include <functional>
#include <memory>
#include "DebugDelete.h"
template<typename T>
class shared_p
{
	T *_ptr=nullptr;
	std::size_t *_count=nullptr;
	std::function<void(T*)> deleter{ DebugDelete() };
	void free()
	{
		if (_ptr)
		{
			if (--*_count == 0)
			{
				delete _count;
				deleter(_ptr);
			}
			_ptr = nullptr;
			_count = nullptr;
		}
	}
public:
	shared_p() = default;
	shared_p(T *ptr, std::function<void(T*)> del = DebugDelete()) :
		_ptr(ptr), deleter(del),_count(new std::size_t(1)) {}
	shared_p(std::shared_ptr<T> &&sp, std::function<void(T*)> del = DebugDelete())	//16.29
	{
		if (sp.unique())
		{
			*this = shared_p(new T(*sp), del);
		}
		else
			throw std::runtime_error("unique error!!");
	}
	shared_p(shared_p &&s)noexcept:_ptr(std::move(s._ptr)),_count(std::move(s._count)),deleter(std::move(s.deleter))
	{
		s._ptr = nullptr;
		s._count = nullptr;
		s.deleter = nullptr;
	}

	shared_p &operator=(shared_p &s)
	{
		if(_ptr!=nullptr)
			free();
		_ptr = s._ptr;
		_count = s._count;
		deleter = s.deleter;
		++*_count;
		return *this;
	}
	shared_p &operator=(shared_p &&s)
	{
		if (_ptr != nullptr)
			free();
		_ptr = s._ptr;
		_count = s._count;
		deleter = s.deleter;
		s._count = nullptr;
		s._ptr = nullptr;
		s.deleter = nullptr;
		return *this;
	}

	operator bool()const
	{
		return _ptr ? true : false;
	}

	T &operator*()const
	{
		return *_ptr;
	}

	T *operator->()const
	{
		return _ptr;
	}

	std::size_t use_count()const
	{
		return *_count;
	}

	T *get()const noexcept
	{
		return _ptr;
	}

	bool unique()const noexcept
	{
		return *_count == 1;
	}

	void swap(shared_p &s)
	{
		::__ExceptionPtrSwap(*this, s);
	}

	void reset()noexcept
	{
		free();
	}
	void reset(T *s, std::function<void(T*)> &del=DebugDelete())
	{
		if (_ptr != p)
		{
			free();
			_ptr = s;
			_count = new std::size_t(1);
			deleter = del;
		}
	}
	void reset(std::function<void(T*)> &del = DebugDelete())
	{
		deleter = del;
	}

	~shared_p()
	{
		free();
	}
};
#pragma once	//Bolb.h
#include <iostream>
#include <string>
#include <vector>
#include <initializer_list>
#include <memory>	//make_shared
#include "shared_p.h"
template<typename T> class Blob;

template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T>
class Blob
{
public:

	friend bool operator==<T>(const Blob &l, const Blob &r);
	typedef T value_type;
	typedef typename std::vector<T>::size_type size_type;	//把size_type视为类型名,忽略vector里同名的(如果有)静态变量
	Blob();
	Blob(std::initializer_list<T> il);
	template<class U>
	Blob(U b, U e);
	size_type size()const {						//返回元素数量
		return data->size();
	}
	bool empty()const {							//是否为空
		return data->empty();
	}
	void push_back(const T &t) {				//添加元素到末尾
		data->push_back(t);
	}
	void push_back(T &&t) {
		data->push_back(std::move(t));
	}
	void pop_back();							//弹出末尾元素
	T &back();									//返回末尾元素的引用
	T &operator[](size_type i);					//返回第i个元素的引用
private:
	shared_p<std::vector<T>> data;
	void check(size_type i, const std::string &msg)const;
};

template<typename T>
void Blob<T>::check(size_type i, const std::string &msg)const {
	if (i >= data->size())
		throw std::out_of_range(msg);
}
template<typename T>
T &Blob<T>::back() {
	check(0, "back on empty Blob");
	return data->back();
}
template<typename T>
T &Blob<T>::operator[](size_type i) {
	check(i, "subscript out range");
	return (*data)[i];
}
template<typename T>
void Blob<T>::pop_back() {
	check(0, "pop_back on empty Blob");
	data->pop_back();
}
template<typename T>
Blob<T>::Blob() :data(std::make_shared<std::vector<T>>()) {
}
template<typename T>
Blob<T>::Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {
}

template<typename T>
bool operator==(const Blob<T> &l, const Blob<T> &r) {
	if (l.data != r.data)
		return false;
	return true;
}

template<class T>
template<class U>
Blob<T>::Blob(U b, U e) :data(std::make_shared<std::vector<T>>(b, e))
{
}
#include "Blob.h"
int main()
{
	using namespace std;
	int vi[] = { 1,2,3,4,5,6 };
	vector<int> vint(begin(vi), end(vi));
	Blob<int> b(vint.begin(),vint.end());
	for (typename Blob<int>::size_type i = 0; i != b.size(); ++i)
	{
		cout << b[i];
	}
	system("pause");
	return 0;
}

16.31

在类内部定义的方法默认内联,unique_ptr内保存删除器的是一歌函数指针,所以并不会内联而是跳转

16.32

编译器通过实参的类型类推断模板的参数

16.33

一种是非const到const的转换

另外一种是数组或函数到指针的转换

16.34

a、非法,实参是两个不同的类型,前者为 char [3],后者为 char [6]

b、合法,T为const char [4]

16.35

a、合法,T为char,const char被转换为int

b、合法,T为double,float被转换为int

c、合法,T为char

d、非法,实参类型不统一,前者是double,后者是float

16.36

a、T为int*

b、T1和T2都是int*

c、T为const int*

d、都是const int*

e、非法,实参类型不相同,int*与const int*

f、T1为int*,T2为const int*

16.37

不能,该函数只能接受一个模板参数类型

16.38

该函数接收的实参是迭代器或指针,如果不给出实参类型,那么就不知道分配内存的大小

make_shared根据指定的实参类型分配合适的空间,并发返回一个指向这块空间的shared_ptr

16.39

compare<string>

16.40

合法、因为decltype会推导表达式的内容

所以需要改类型支持该表达式的操作:decltype(*beg+0);需要类型支持operator+操作

返回类型取决于该操作符operator的返回值

16.41

template<typename T>

auto sum(T &a,T &b)->decltype(a+b)        //制定返回值的类型

{

return a+b;

}

16.42

a、i为左值,T为int&,val:int& &&折叠为int&

b、ci为左值,T为const int&,val:const int & &&折叠为const int&

c、i*ci为右值,T为int&&,val:T&& &&折叠为int&&

16.43

表达式i=ci最终留下的是左值,所以T为T&,val为int&

16.44

1、template<typename T> void g(T);

a、T为int,val为int

b、T为int,val为int,const被忽略,因为是按值传递

c、T为int,val为int,实参是右值,但是按值传递给形参

2、template<typename T> void g(const T&);

a、T为int,val为const int&

b、T为int,val为const int&

c、T为int&&,val为const int& &&,折叠为const int&

16.45

当实参为42时,编译器解析T为一个右值:int&&,所以val为:int&& &&,折叠后为int&&

当实参为int类型变量时,编译器解析T为一个左值:int&,所以val为:int& &&,折叠后为int&

在第一次传递时,T为int&&,这对于vector没有错误。

但是第二次传递时,T为int&,这样会出现一个错误:未初始化的左值

16.46

	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指向的地址
	}

作用:把elem的所有元素移动到dest的空间里

16.47

#include <vector>
#include <iostream>
template <typename F,typename T1,typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
	f(std::forward<T2>(t2), std::forward<T1>(t1));
}
void pp(int a, int &b)
{
	std::cout << a << " " << ++b << std::endl;
}
void gv(int &a, int &b)
{
	a += b;
	b = a - b;
	a = a - b;
}
int main()
{
	using namespace std;
	int a = 40, b = 86;
	flip(pp,a, b);
	flip(gv, a, b);
	cout << a << " " << b << endl;
	system("pause");
	return 0;
}

16.49、16.50

#include <iostream>

template<typename T> void f(T t) {
	std::cout << "f(T):" << t << std::endl;
}
template<typename T> void f(const T *t) {
	std::cout << "f(const T *):" << t << " " << *t << std::endl;
}
template<typename T> void g(T t) {
	std::cout << "g(T):" << t << std::endl;
}
template<typename T> void g(T *t) {
	std::cout << "f(T *):" << t << " " << *t << std::endl;
}
int main()
{
	using namespace std;
	int i = 42, *p = &i;
	const int ci = 0, *p2 = &ci;
	g(42);			//g(T)<span style="white-space:pre">		</span>const int更匹配T
	g(p);			//g(T*)   <span style="white-space:pre">	</span>p是指针更匹配T*
	g(ci);			//g(T)
	g(p2);			//g(T*)
	f(42);			//f(T)
	f(p);			//f(T)
	f(ci);			//f(T)
	f(p2);			//f(const T*)<span style="white-space:pre">		</span>更加特例化

	system("pause");
	return 0;
}

16.51、16.52

#include <iostream>
#include <string>
template<typename T,typename... Args>
void foo(const T &t, Args... args)
{
	std::cout << "Args:" << sizeof...(Args) << "\targs:" << sizeof...(args) << std::endl;
}

int main()
{
	using namespace std;
	int i = 0;
	double d = 3.14;
	string s = "c++ primer";
	foo(i, s, 42, d);					//Args:3	args:3
	foo(i, 42, "hello");				//Args:2	args:2
	foo(d, s);							//Args:1	args:1
	foo("hi");							//Args:0	args:0
	foo("c++", '5', 2016, 4.2, i, s);	//Agrs:5	args:5
	system("pause");
	return 0;
}

16.53

#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;
}

16.54

缺少“<<”操作符的定义:

class Test
{};
...
Test t;
print(cout,t);//二进制“<<”: 没有找到接受“const aaa”类型的右操作数的运算符(或没有可接受的转换)

16.55

题目无法理解,会的同学请@我

16.56

#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;
}

16.57

前者使用的是initialize_list,只能传递相同类型的实参,相比之下可变参数更灵活

16.58

#pragma once
#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;	//指向内存尾
}

16.59

16.60

可接受可变参数模板,转发其参数把初始化一个内存与没陪空间,返回一个shared_ptr

16.61

#include <memory>
#include <iostream>
#include <string>
template<typename T, typename... Args>
std::shared_ptr<T> make_shared(Args&&... args)
{
	return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
}

int main()
{
	auto p = make_shared<int>(40);
	std::cout << *p << std::endl;
	auto cp = make_shared<std::string>(10, 'a');
	std::cout << *cp << std::endl;
	system("pause");
	return 0;
}

16.62

#pragma once
#include <iostream>
#include <string>
class Sales_data
{
	std::string bookNo;
	unsigned units_sold;
	double revenue;
	double avg_price()const { return units_sold ? revenue / units_sold : 0; }
public:
	Sales_data(const std::string &s=std::string(), unsigned n = 0, double p = 0) :bookNo(s), units_sold(n), revenue(p) {}
	Sales_data(std::istream &is);
	std::string isbn()const { return bookNo; }
	Sales_data &operator+=(const Sales_data &s);
	friend std::hash<Sales_data>;
	friend std::ostream &operator<<(std::ostream &os, const Sales_data &s);
	friend std::istream &operator>>(std::istream &is, Sales_data &s);
	friend bool operator==(const Sales_data &ls, const Sales_data &rs);
	friend Sales_data operator+(const Sales_data &ls, const Sales_data &rs);
	friend std::ostream &print(std::ostream &os, const Sales_data &s);
	friend std::istream &read(std::istream &is, Sales_data &s);
};
bool operator!=(const Sales_data &ls, const Sales_data &rs);
Sales_data add(const Sales_data &ls, const Sales_data &rs);

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.bookNo) ^ hash<unsigned>()(s.units_sold) ^ hash<double>()(s.revenue);
		}
	};
}
#include "Sales_data.h"

Sales_data::Sales_data(std::istream &is)
{
	is >> *this;
}

Sales_data &Sales_data::operator+=(const Sales_data &s)
{
	units_sold += s.units_sold;
	revenue += s.revenue;
	return *this;
}

std::ostream &operator<<(std::ostream &os, const Sales_data &s)
{
	os << s.isbn() << " " << s.units_sold << " " << s.revenue << " " << s.avg_price();
	return os;
}

std::istream &operator>>(std::istream &is, Sales_data &s)
{
	double price;
	is >> s.bookNo >> s.units_sold >> price;
	if (is)
		s.revenue = s.units_sold*price;
	else
		s = Sales_data();
	return is;
}

bool operator==(const Sales_data &ls, const Sales_data &rs)
{
	return ls.bookNo == rs.bookNo&&ls.units_sold == rs.units_sold&&ls.revenue == rs.revenue;
}
bool operator!=(const Sales_data &ls, const Sales_data &rs)
{
	return !(ls == rs);
}

Sales_data operator+(const Sales_data &ls, const Sales_data &rs)
{
	Sales_data temp = ls;
	temp += rs;
	return temp;
}

Sales_data add(const Sales_data &ls, const Sales_data &rs)
{
	Sales_data temp = ls;
	temp += rs;
	return temp;
}

std::ostream &print(std::ostream &os, const Sales_data &s)
{
	os << s.isbn() << " " << s.units_sold << " " << s.revenue << " " << s.avg_price();
	return os;
}

std::istream &read(std::istream &is, Sales_data &s)
{
	double price;
	is >> s.bookNo >> s.units_sold >> price;
	s.revenue = s.units_sold*price;
	return is;
}
#include <memory>
#include <unordered_set>
#include "Sales_data.h"

int main()
{
	//! test for ex16.62
	std::unordered_multiset<Sales_data> mset;
	Sales_data sd("Bible", 10, 0.98);

	mset.emplace(sd);
	mset.emplace("C++ Primer", 5, 9.99);

	for (const auto &item : mset)
		std::cout << "the hash code of " << item.isbn()
		<< ":\n0x" << std::hex << std::hash<Sales_data>()(item)
		<< "\n";
	system("pause");
	return 0;
}

16.63、16.64

#pragma once
#include <vector>
#include <string>
#include <cstring>

template<typename T>
std::size_t count(const std::vector<T> &vec, T value)
{
	std::size_t count = 0;
	for (auto &x : vec)
		count += (x == value) ? 1 : 0;
	return count;
}

template<>
std::size_t count(const std::vector<char *> &vec, char *value)
{
	std::size_t count = 0;
	for (auto &x : vec)
		count += (strcmp(x, value) == 0) ? 1 : 0;
	return count;
}
#include <iostream>
#include "标头.h"

int main()
{
	using namespace std;

	//16.63
	vector<double> dv = { 5,6,8,3,5,5,6,3,4 };
	vector<int> iv = { 2,3,5,6,3,3,4,8,3,5,1 };
	vector<string> sv = { "q","w","q","q","a","d","f","q" };
	cout << count(dv, 5.0) << " " << count(iv, 3) << " " << count<string>(sv, "q");

	//16.64
	vector<char *> cpv = { "c++","primer","4th","hello","world","c++" };
	cout << count<char *>(cpv, "c++");

	system("pause");
	return 0;
}

16.65

#pragma once
#include <sstream>
#include <string>

template<typename T>
std::string debug_rep(T *t)
{
	std::ostringstream ret;
	ret << t;
	return ret.str();
}
template<>
std::string debug_rep(char *t)
{
	return std::string(t);
}
template<>
std::string debug_rep(const char *t)
{
	return std::string(t);
}
#include "标头.h"
#include <iostream>

int main()
{
	using namespace std;
	char c[] = "c++ primer 5";
	const char *p = c;
	cout << debug_rep(c) << endl;
	cout << debug_rep(p) << endl;
	system("pause");
	return 0;
}

16.66

重载会改变匹配优先度

16.67

不会影响,

特化的模板匹配优先度和模板级别一致,还是非模板优先度最高

2016年4月9日23:34:23

过了那么久...连我自己都怀疑自己的耐心了

时间: 2024-10-09 23:18:58

c++primer第五版第十六章练习的相关文章

c++primer第五版第十九章练习

19.1 #include <iostream> #include <cstdlib> void *operator new(std::size_t n){ std::cout << "new(size_t)\n"; if (void *mem = malloc(n)) return mem; else throw std::bad_alloc(); } void operator delete(void *mem) noexcept{ std::c

C++Primer第五版习题解答---第一章

C++Primer第五版习题解答---第一章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2022/1/7 第一章:开始 练习1.3 #include<iostream> int main() { std::cout << "hello, world" << std::endl; return 0; } 练习1.4: #include<iostream> int main() { int

C++ Primer 第五版:第1 章

*****C++ Primer 第五版第1章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 1.1 编写一个简单的C++程序 函数:依据我个人理解,C/C++的函数是一个能够完成一个功能的模块. 完整函数的组成: ①返回类型:不一定有返回值,故不一定有返回类型 ②函数名:根据名字标识完成特定功能的模块,必须存在 ③形参列表:可能没有参数传入,不一定存在 ④函数体:一个完整的函数应该是有

C++ Primer 第五版:第2章

*****C++ Primer 第五版第2章学习笔记***** *****实验代码在Red Hat 6.6或VS 2013中调试***** *****文章内容依据当前知识撰写,存在认识的局限性***** 今天学习C++ Primer 的第2章,还没有看完,先写一点看书的心得和笔记. 对象类型决定对象包含的数据和能参与的运算操作,同时还决定了存储空间大小.算术表达式中不要使用char,因为不同机器实现不一样,导致结果不同.单精度计算不一定比双精度快. C++类型不匹配时,是自动进行类型的转换. C

C Primer Plus (第五版) 第六章 编程练习

第六章 C控制语句:循环 编程练习: 1.编写一个程序,创建一个具有26个元素的数组,并在其中存储26个小写字母. 并让该程序显示该数组的内容. #include <stdio.h> int main(void) { char ch[26]; int i; for (i = 0; i < 26; i++) ch[i] = 'a' + i; for (i = 0; i < 26; i++) printf("%c ", ch[i]); printf("\n

C++ Primer中文版(第五版)——第六章 函数

6.1函数基础 一个典型的函数定义包括以下几个部分:返回类型(return type).函数名字.由0个或多个形参组成的参数列表以及函数体.其中,形参以逗号隔开,形参的列表位于一对圆括号之内.函数执行的操作在语句块中说明,该语句块称为函数体. 我们通过调用运算符(call operator)来执行函数.调用运算符的形式是一对圆括号,它作用于一个表达式,该表达式是函数或者是指向函数的指针:圆括号之内是一个用逗号隔开的实参列表,我们用实参初始化函数的形参.调用表达式的类型就是函数的返回类型. 编写函

《C++ Primer》读书笔记—第十六章 模板与泛型编程

---恢复内容开始--- 声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 1.面向对象编程和泛型编程都是处理在编写程序时不知道类型的情况,不同之处在于,OOP能处理类型在程序运行之前都未知的情况,而在泛型编程中,在编译时就能获知类型了. 2.泛型编程与面向对象编程一样,都依赖于某种形式的多态性.面向对象编程中的多态性在运行时应用于存在继承关系的类. 3.在泛型编程中,我们所编写的类和函数能够多态地用于跨越编译

c++ Primer 第五版习题答案第二章

练习2.1 Q: 类型int.long.long long和short的区别是什么,无符号和带符号类型的区别是什么?float和double的区别是什么? A:int. long. long long和short尺寸不同,表示的数据范围不同.无符号只能表示0和正数,无符号还可以表示负数.float为单精度浮点数,double为双精度,一般来说,float占4字节,double占8字节. 练习2.2 Q: 计算按揭贷款时,对于利率.本金和付款分别应选择何种数据类型?说明你的理由. A: 利率应该用

C Primer Plus (第五版) 第十六章 C预处理器和C库 编程练习

第十六章 C预处理器和C库 开发一个包含您需要使用的预处理器定义的头文件 //max.h  #ifndef _MAX_H_     #define _MAX_H_     #define MAX(X, Y) ((X)>(Y)?(X):(Y)) #endif 2.两个数的调和平均数可用如下方法得到:首先对两数的倒数取平均值,最后再取倒数.使用#define指令定义一个宏"函数"执行这个运算.编写一个简单的程序测试该宏. #include <stdio.h> #defin