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 不会,因为模板的特例化是模板的实例而不是重载。

猜你喜欢

转载自blog.csdn.net/qq_25037903/article/details/83051251
今日推荐