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题目的就是本节主题:效率与灵活性的例子.