1. 程式人生 > >c++ primer 第十六章習題

c++ primer 第十六章習題

c++ primer 第十六章習題


練習16.1 例項化是指傳遞給模板相應的模板引數,使其生成對應型別的函式體或是型別定義。
練習16.2

#include <iostream>
#include <string>
#include <vector> 
#include "Sales_data.cc"


using namespace std;

template <typename T>
int compare(const T& a, const T& b) {
	if (less<T>()(a,b)) return -1;
	if (less<T>()(b,a)) return 1;
	return 0;
}

int main() {
	int a = 1, b = 2;
	double c = 1.0, d = 3.0;
	Sales_data s1("nihao"), s2("haha");
	cout << compare(a,b) <<endl;
	cout << compare(c,d) <<endl;
	cout << compare(s1,s2) <<endl;

	return 0;
}

練習16.4

#include <iostream>
#include <string>
#include <vector>
#include <list>

using namespace std;

template <typename T,typename ITER>
ITER find(const ITER& begin, const ITER& end, T value) {
	ITER tmp = begin;
	while(tmp != end) {
		if(*tmp == value)
			return tmp;
		tmp++;
	}
	return end;
}

int main() {
	vector<int> a = {1,2,3,4,5};
	list<string> l = {"heh", "nihao","wawa","world"};
	auto iter1 = find(a.begin(), a.end(), 3);
	if(iter1 != a.end())
		cout << "find: "<<*iter1<<endl;
	auto iter2 = find(l.begin(), l.end(), "world");
	if(iter2 != l.end())
		cout << "find: "<<(*iter2)<<endl;

	return 0;
}

練習16.5

template <typename T, unsigned N>
void print(T (&arr)[N]) {
	for(T a : arr)
		cout << a << endl;
}

int main() {
	int a[] = {1,2,3,4,5};
	string l[] = {"heh", "nihao","wawa","world"};
	print(a);
	print(l);

	return 0;
}

練習16.6

template <typename T, unsigned N>
T* begin1(T (&arr)[N]) {
	return arr;
}

template <typename T, unsigned N>
T* end1(T (&arr)[N]) {
	return arr+N;
}
int main() {
	int a[] = {1,2,3,4,5};
	string l[] = {"heh", "nihao","wawa","world"};
	cout << *begin1(a)<<endl;
	cout << end1(l)-begin1(l)<<endl;

	return 0;
}

練習16.7

template<typename T, unsigned N>
constexpr unsigned size(T (&arr)[N]) {
	return N;
}

練習16.8 有很多類中沒有定義<符號
練習16.9 函式模板是一個公式,針對不同型別的實參呼叫生成對應版本的函式。類模板是一個類的藍圖,不能像函式模板一樣自動推斷模板引數。使用時需要使用顯式的型別。
練習16.10 編譯器生成對應引數型別的類的定義,包括內聯的成員函式。
練習16.11 使用模板類時需要給出顯式型別。
練習16.13 一對一友元關係
練習16.14 15

#ifndef SCREEN_H
#define SCREEN_H

#include <string>
#include <iostream>

template<unsigned H, unsigned W> class Screen;
template<unsigned H, unsigned W> 
std::ostream& operator<<(std::ostream& os, const Screen<H,W>&);
template<unsigned H, unsigned W> 
std::istream& operator>>(std::istream& is, Screen<H,W>&);

template <unsigned H, unsigned W>
class Screen
{
public:
	typedef std::string::size_type pos;
	Screen() = default;
	Screen(char c): contents(W*H,c) {}

	char get() const {
		return contents[cursor];
	}

    friend std::ostream& operator<<<H,W>(std::ostream& os, const Screen<H,W>& c);

    friend std::istream& operator>><H,W>(std::istream& is, Screen<H,W>& c);
	Screen& move(pos r, pos c);

private:
	pos cursor = 0;
	pos height = H, width = W;
	std::string contents;
	
};

template<unsigned H, unsigned W>
Screen<H,W>& Screen<H,W>::move(pos r, pos c) {
	cursor = r*W+c;
	return *this;
}

template<unsigned H, unsigned W> 
std::istream& operator>>(std::istream& is, Screen<H,W>& c) {
    	char a;
    	is >> a;
    	std::string tmp(H*W,a);
    	c.contents = tmp;
    	return is;
    }

template<unsigned H, unsigned W> 
std::ostream& operator<<(std::ostream& os, const Screen<H,W>& c) {
    	for(int i = 0; i < c.height; i++)
    		os << c.contents.substr(i*W,W);
    	return os;
    }
#endif

練習16.14,15

#ifndef SCREEN_H
#define SCREEN_H

#include <string>
#include <iostream>

template<unsigned H, unsigned W> class Screen;
template<unsigned H, unsigned W> 
std::ostream& operator<<(std::ostream& os, const Screen<H,W>&);
template<unsigned H, unsigned W> 
std::istream& operator>>(std::istream& is, Screen<H,W>&);

template <unsigned H, unsigned W>
class Screen
{
public:
	typedef std::string::size_type pos;
	Screen() = default;
	Screen(char c): contents(W*H,c) {}

	char get() const {
		return contents[cursor];
	}

    friend std::ostream& operator<<<H,W>(std::ostream& os, const Screen<H,W>& c);

    friend std::istream& operator>><H,W>(std::istream& is, Screen<H,W>& c);
	Screen& move(pos r, pos c);

private:
	pos cursor = 0;
	pos height = H, width = W;
	std::string contents;
	
};

template<unsigned H, unsigned W>
Screen<H,W>& Screen<H,W>::move(pos r, pos c) {
	cursor = r*W+c;
	return *this;
}

template<unsigned H, unsigned W> 
std::istream& operator>>(std::istream& is, Screen<H,W>& c) {
    	char a;
    	is >> a;
    	std::string tmp(H*W,a);
    	c.contents = tmp;
    	return is;
    }

template<unsigned H, unsigned W> 
std::ostream& operator<<(std::ostream& os, const Screen<H,W>& c) {
    	for(int i = 0; i < c.height; i++)
    		os << c.contents.substr(i*W,W);
    	return os;
    }
#endif

練習16.15 <<過載和 >>過載為友元
練習16.17 沒有不同 需要說明型別的時候
練習16.18 (a)缺了一個typename (b)不能重用T © inline在返回值型別之前
(d) 返回值未說明 (e) 正確 但隱藏了外層的Ctype
練習16.19

#include <iostream>
#include <string>
#include <vector>

using namespace std;

template <typename T>
void print(const T& v) {
	typename T::size_type index = 0;
	while(index < v.size())
		cout << v[index++]<<endl;
}

int main() {
	vector<string> v = {"hello","it's","me"};
	print(v);
	return 0;
}

練習16.20

template <typename T>
void print(const T& v) {
	typename T::const_iterator iter = v.begin();
	while(iter != v.end())
		cout << *iter++<<endl;
}

練習16.21

#include <iostream>
#include <string>
#include <vector>


class debugDelete
{
public:
	debugDelete(const std::string& p = "unique_ptr", std::ostream& o = std::cerr):s(p),os(o){};
	template<typename T> void operator()(T* p) {
	os << "deleting "<<p<<std::endl;
	delete p;
}
private:
	std::string s;
	std::ostream os;
};

練習16.24

template <typename T> 
template <typename It>   
    Blob<T>::Blob(It b, It e):
              data(std::make_shared<std::vector<T>>(b, e)) { }

練習16.25 第一個是宣告外部有此例項的模板類。第二個是定義特定模板類例項。
練習16.26 不可以,因為例項化時會呼叫其建構函式。
練習16.27 TTTFFT
練習16.31 定義unique_ptr時同時輸入DebugDelete類的型別作為模板實參,然後將其例項化類中的該型別實參對應的成員賦值為DebugDelete類的物件。
練習16.32 判斷實參型別與型別名是否與模板匹配
練習16.33 1.從非const物件的引用或指標賦值給const型別的引用或指標。2.陣列型別轉為對應指標型別。
練習16.34 (a)不合法,陣列長度不匹配 (b)合法
練習16.35 TTTF
練習16.36 TTTTFT
練習16.37 可以,使用顯式實參
練習16.38 用來指定返回的共享指標的例項化型別。不指定的話無法知道需要分配的記憶體大小。
練習16.39 compare<string>(a,b)
練習16.40 合法,需要指向的型別支援與整型的加法
練習16.41

template<typename T>
auto sum(T lhs, T rhs) -> decltype( lhs + rhs)
{
    return lhs + rhs;
}

練習16.42 (a) T: int& val: int& (b) const int& const int& © int int&&
練習16.43 int&
練習16.44 1、a、T為int,val為int
b、T為int,val為int,const被忽略,因為是按值傳遞
c、T為int,val為int,實參是右值,但是按值傳遞給形參
2、a、T為int,val為const int&
b、T為int,val為const int&
c、T為int&&,val為const int& &&,摺疊為const int&
練習16.45 正確,T是int。 錯誤,T是int&因此vector定義失敗。
練習16.46 從dest指標位置開始使用elem指向的物件的右值引用構造size()個。
練習16.47

template<typename F, typename T1,typename T2>
void flip(F f, T1&& t1, T2&& t2) {
	f(std::forward<T2>(t2),std::forward<T1>(t1));
}

練習16.48

template<typename T>
string debug_rep(const T& t) {
	ostringstream ret;
	res << t;
	return t.str();
}

template<typename T>
string debug_rep(T* p) {
	ostringstream ret;
	ret << "pointer: "<< p;
	if (p)
		ret << " "<< debug_rep(*p);
	else
		ret << "null pointer";
	return ret.str();
}

練習16.49 前f 後 前g 後 前f 後 前g 後
練習16.51 52

using namespace std;

template <typename T,typename... Args>
void foo(const T& t, const Args& ... rest) {
	cout << sizeof...(Args)<<endl;
	cout << sizeof...(rest)<<endl;
}

int main() {
	vector<string> v = {"hello","it's","me"};
	int a = 1;
	string c = "shif";
	double k = 2.0;
	foo(a,v,c,k);
	foo(a,v,c);
	foo(a,v);
	foo(a);
	return 0;
}

練習16.53

template<typename T>
void print(ostream& os, const T& t) {
	os << t;
}

template<typename T, typename... Args>
void print(ostream& os, const T& t, const Args& ... rest) {
	os << t << ",";
	print(os,rest...);
}

int main() {
	int a = 1;
	string c = "shif";
	double k = 2.0;
	print(cout,a,c,k);
	return 0;
}

練習16.54 會報錯
練習16.55 會執行到引數少的無法匹配然後報錯
練習16.56

template<typename T>
string debug_rep(T* p) {
	ostringstream ret;
	ret << "pointer: "<< p;
	if (p)
		ret << " "<< debug_rep(*p);
	else
		ret << "null pointer";
	return ret.str();
}

template<typename... Args>
void error_msg(ostream& os, const Args&... args) {
	print(os, debug_rep(args)...);
}

練習16.57 可變引數版本可以接收不同數量不同型別的報錯資訊但是需要遞迴。固定型別的不需要遞迴,但不夠靈活。
練習16.58

template<typename... Args>
inline
void StrVec::emplace_back(Args&&... args) {
	chk_n_alloc();
	allocator.construct(first_free++,std::forward<Args>(args)...);
}

練習16.59 會呼叫construct函式,construct函式會呼叫string的賦值建構函式。
練習16.60 61

template<typename T,typename... Args>
shared_ptr<T> make_shared(Args... args) {
	return shared_ptr<T>(new T(std::forward<Args>(args)...));
}

練習16.62

namespace std {
	class  hash<Sales_data> {
		typedef size_t result_type;
		typedef Sales_data argument_type;
		size_t operator()(const Sales_data& s) {
			return hash<string>()(s.bookNo)^hash<unsigned>()(s.units_sold)^hash<double>()(s.revenue);
		}
	}
}

練習16.63 64

template<typename T>
size_t count(const vector<T>& v, T a) {
	size_t res = 0;
	for(T t : v)
		if (t == a)
			res++;
	return res;
}

template<>
size_t count(const vector<const char*>& v, const char* a) {
	size_t res = 0;
	for(auto t : v)
		if (strcmp(t,a) == 0)
			res++;
	return res;
}


int main() {
	vector<double> dv = {1,2,3,4,5,6,6,2,3,2,2};
	vector<int> di = {1,1,1,1,2,3,3,2,1,1};
	vector<string> ds = {"hello", "hello","its","its","me"};
	vector<const char*> dc = {"hello", "hello","its","its","me"};
	cout << count(dv,2.0)<<endl;
	cout << count(di,1)<<endl;
	cout << count(ds,string("hello"))<<endl;
	cout << count(dc,"hello")<<endl;
	return 0;
}

練習16.65

template<>
string debug_rep(char* p) {
	return debug_rep(string(p));
}

template<>
string debug_rep(const char* p) {
	return debug_rep(string(p));
}

練習16.66 過載要寫的函式太多,每種型別都寫一個,但不會匹配錯誤。特例化只需要對特定型別進行單獨編寫,但是有可能無法匹配上或是忘記宣告導致呼叫錯誤的函式。
練習16.67 不會,因為模板的特例化是模板的例項而不是過載。