c++ primer 第十六章习题

c++ primer 第十六章习题


练习16.1 实例化是指传递给模板相应的模板参数,使其生成对应类型的函数体或是类型定义。
练习16.2

#include 
#include 
#include  
#include "Sales_data.cc"


using namespace std;

template 
int compare(const T& a, const T& b) {
	if (less()(a,b)) return -1;
	if (less()(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) <

练习16.4

#include 
#include 
#include 
#include 

using namespace std;

template 
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 a = {1,2,3,4,5};
	list l = {"heh", "nihao","wawa","world"};
	auto iter1 = find(a.begin(), a.end(), 3);
	if(iter1 != a.end())
		cout << "find: "<<*iter1<

练习16.5

template 
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 
T* begin1(T (&arr)[N]) {
	return arr;
}

template 
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)<

练习16.7

template
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 
#include 

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

template 
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<<(std::ostream& os, const Screen& c);

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

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

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

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

template 
std::ostream& operator<<(std::ostream& os, const Screen& 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 
#include 

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

template 
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<<(std::ostream& os, const Screen& c);

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

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

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

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

template 
std::ostream& operator<<(std::ostream& os, const Screen& 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 
#include 
#include 

using namespace std;

template 
void print(const T& v) {
	typename T::size_type index = 0;
	while(index < v.size())
		cout << v[index++]< v = {"hello","it's","me"};
	print(v);
	return 0;
}

练习16.20

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

练习16.21

#include 
#include 
#include 


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

练习16.24

template  
template    
    Blob::Blob(It b, It e):
              data(std::make_shared>(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(a,b)
练习16.40 合法,需要指向的类型支持与整型的加法
练习16.41

template
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
void flip(F f, T1&& t1, T2&& t2) {
	f(std::forward(t2),std::forward(t1));
}

练习16.48

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

template
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 
void foo(const T& t, const Args& ... rest) {
	cout << sizeof...(Args)< 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
void print(ostream& os, const T& t) {
	os << t;
}

template
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
string debug_rep(T* p) {
	ostringstream ret;
	ret << "pointer: "<< p;
	if (p)
		ret << " "<< debug_rep(*p);
	else
		ret << "null pointer";
	return ret.str();
}

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

练习16.57 可变参数版本可以接收不同数量不同类型的报错信息但是需要递归。固定类型的不需要递归,但不够灵活。
练习16.58

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

练习16.59 会调用construct函数,construct函数会调用string的赋值构造函数。
练习16.60 61

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

练习16.62

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

练习16.63 64

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

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


int main() {
	vector dv = {1,2,3,4,5,6,6,2,3,2,2};
	vector di = {1,1,1,1,2,3,3,2,1,1};
	vector ds = {"hello", "hello","its","its","me"};
	vector dc = {"hello", "hello","its","its","me"};
	cout << count(dv,2.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 不会,因为模板的特例化是模板的实例而不是重载。

你可能感兴趣的:(C++)