C++Prime第十六章 前31题

C++Prime第十六章 前31题

练习16.1

编译器使用推断出的模板参数代替对应的模板参数,常见出模板的一个实例,这就是实例化.

练习16.2

template<typename T>
int compare(const T& t1, const T& t2) {
	if (t1 < t2) return -1;
	if (t2 < t1) return 1;
	return 0;
}
int main()
{
	cout << compare(1, 2) << endl;
	return 0;
}

练习16.3

大体是没有找到接受 < 操作的运算符

练习16.4

template<class T1,typename T2>
T1 Find(const T1& beg, const T1& end, const T2& val)
{
	for (auto p = beg; p != end; ++p)
		if (*p == val)
			return p;
	return end;
}

int main()
{
	vector<int> ivec{ 1,2,4,3,5,6 };
	if (Find(ivec.begin(), ivec.end(), 3) != ivec.end())
		cout << "ivec Find it" << endl;
	
	list<string> slst{ "hello","word","ni","hao" };
	if (Find(slst.begin(), slst.end(), string("ni")) != slst.end())
		cout << "slst Find it" << endl;
	return 0;
}

练习16.5

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

int main()
{
	int a[] = {1,2,3,4,5};
	print(a);

	return 0;
}

练习16.6

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

template<typename T,unsigned N>
const T* myEnd(const T(&arr)[N])
{
	return arr + N;
}
int main()
{
	int a[] = {1,2,3,4,5};
	//print(a);
	Find(myBegin(a), myEnd(a), 3);

	return 0;
}

练习16.7

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

int main()
{
	int a[] = {1,2,3,4,5};
	//print(a);
	//Find(myBegin(a), myEnd(a), 3);
	cout << cap(a) << endl;
	return 0;
}

练习16.8

对容器友好,不是所有的元素都定义了<运算符,但是一般定义了!=操作

练习16.9

函数模板:是一个通用的函数模板,而不是为每个类型都定义一个新函数.可以看做一个公式.
类模板:一个通用的类模板,用来生成类的蓝图.

练习16.10

类模板实例化时,使用者必须提供额外的信息,这些额外信息就是模板实参列表,它被绑定到模板参数.编译器用这些模板实参来实例化出特定的类.

练习16.11

List模板类内定义出现的ListItem是模板,必须实例化.

练习16.12

课本照敲

练习16.13

一对一友好关系.避免出现不同类型的BlobStr相等.

练习16.14

template<unsigned L,unsigned W> class Screen {
public:
	Screen() :length(L), width(W) { }
private:
	unsigned length;
	unsigned width;
};

int main()
{
	Screen<1,2>();

	return 0;
}

练习16.15

template<unsigned L,unsigned W> class Screen {
public:
	Screen() :length(L), width(W) { }
private:
	unsigned length;
	unsigned width;
	string name;

	friend ostream& operator<<(ostream& os, const Screen<L, W>& s) {
		os << s.name<<" " <<s.length << " " << s.width;
		return os;
	}
	friend istream& operator>>(istream& is, Screen<L, W>& s) {
		is>>s.name;
		return is;
	}
};

int main()
{
	Screen<1,2> s;
	cin >> s;
	cout << s;

	return 0;
}

练习16.16

#pragma once
#pragma once
#include <iostream>
#include <memory>
#include <initializer_list>
#include <algorithm>
using namespace std;
template<typename T> 
class Vec
{
public:
	Vec(const initializer_list<T>& il);
	Vec() :elements(nullptr), first_free(nullptr), cap(nullptr) { }
	Vec(Vec&&) noexcept;										//移动构造函数
	Vec(const Vec&);													//拷贝构造函数
	Vec& operator=(const Vec&);							//拷贝赋值运算符
	Vec& operator=(Vec&&)noexcept;					//移动赋值运算符
	~Vec();																	//析构函数
	void push_back(const T&);									//拷贝元素
	void push_back(T&& s);										//成员函数的移动拷贝版本
	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; }
	void reserve(size_t n);
	void resize(size_t n);
	void resize(size_t n, const T& t);

	T& operator[](size_t n) { return elements[n]; }
	const T& operator[](size_t n)const { return elements[n]; }
private:
	static allocator<T> alloc;
	void check_n_alloc() 
	{
		if (size() == capacity())
			reallocate();
	}
	pair<T*, T*> alloc_n_copy(const T*, const T*);
	void free();							//销毁元素并释放内存
	void reallocate();					//获得更多内存并拷贝已有元素
	T* elements;						//指向数组首元素的指针
	T* first_free;							//指向数组第一个空闲元素的指针
	T* cap;									//指向数组尾后位置的指针

	friend bool operator==<T>(const Vec<T>& t1, const Vec<T>& t2);
	friend bool operator!= <T>(const Vec<T>& t1, const Vec<T>& t2);
};

练习16.17

一般情况,typename 和 class 没有不同
当用来表示作用域的某个类型而不是成员名字时,必须使用typename

练习16.18

(a)非法.U前面必须有typename
(b)错误,T是类型,不能作为形参
©inline位置错误.应放于模板参数列表之后
(d)错误,f4没有返回类型
(e)正确.f5的返回类型和形参类型都由用户输入决定,不一定是char

练习16.19

template <typename T>
void print(T& t)
{
	typename T::size_type i = 0;
	while (i != t.size())
		cout << t[i++] <<" ";
	cout << endl;
}


int main()
{
	vector<int> d{ 1,2,3,4,5,6 };
	print(d);
	return 0;
}

练习16.20

template <typename T>
void print(T& t)
{
	typename T::const_iterator p = t.cbegin();
	while (p != t.cend())
		cout << *p++ <<" ";
	cout << endl;
}

int main()
{
	vector<int> d{ 1,2,3,4,5,6 };
	print(d);
	return 0;
}

练习16.21

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

练习16.22

练习16.23

练习16.24

练习16.25

显式实例化声明vector.
显示定义vector,在此处生成代码.

练习16.26

不可以,不会被实例化

练习16.27

这题不太会.
(a)不实例化,并没有用到f1
(b)?
©实例化.因为要知道Exercise类具体占的空间大小,这个需要再编译时确定
(d)不实例化,使用到sc时才实例化,牧犬sc是一个未定义指针.
(e)实例化,按值传递,此时用到了Stack,实例化的这个
(f)实例化,计算具体空间.

练习16.28

练习16.29

练习16.30

练习16.31

我的理解是,考虑到效率和灵活性一些参数可以并入模板,成为类类型的一部分,减少开销.而对于哪些需要动态确定的,则可以使用指针或者封装了指针的类(如function).
28题目的就是本节主题:效率与灵活性的例子.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值