16.9
函数模版就是一个公式,可用来生成针对特定类型的函数版本,模版定义以关键字template开始,后跟一个模版参数列表,这是一个逗号分割的一个或多个模版参数的列表
类模版是用来生成类的蓝图的,与函数模版的不同之处是,编译器不能为类模版推断模版参数类型,如我们已经多次看到的,为了使用类模版,我们必须在模版名后的尖扩号中提供额外信息
16.10
使用一个类模版时,我们必须提供额外信息,这些额外信息是显示模版实参列表,它们被绑定到模版参数.编译器使用这些模版实参来实例化出特定的类,当实例化一个类时,它会重写Blob模版,将模版参数T的每个实例替换为给定的模版实参,当类模版的静态成员被实例化后,每个实例都会有自己的static成员实例
16.11
修改后如下:
template <typename elemType> class ListItem;
template <typename elemType> class List { public: List<elemType>() = default; List<elemType>(const List<elemType>& ); List<elemType>& operator=(const List<elemType>&); ~List<elemType>() = default; void insert(ListItem<elemType>*ptr, elemType value); //listItem也是需要实例化才能使用的y private: ListItem<elemType> * front, * end; }; int main() { ::List<int> l; for (;;); return 0; } 16.12:
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T>
class Blob{
friend class BlobPtr<T>;
friend bool operator==(const Blob<T>&, const Blob<T>&);
public:
typedef T value_type;
typedef typename vector<T>::size_type size_type;
Blob();
Blob(initializer_list<T> il);
size_type size() const {return data->size();}
bool empty() const {return data->empty();}
void push_back(const T& t){data->push_back(t);}
void push_back(const T && t){data->push_back(std::move(t));}
T& back();
T& operator[](size_type t);
void pop_back();
private:
shared_ptr<vector<T>> data;
void check(size_type i, const string & msg)const;
};
template <typename T>
void Blob<T>::check(size_type i, const string & msg) const{
if(i >= data->size()){
throw out_of_range(msg);
}
}
template <typename T>
T& Blob<T>::back(){
return data->back();
}
template <typename T>
Blob<T>::Blob():data(make_shared(vector<T>)){
}
template <typename T>
Blob<T>::Blob(initializer_list<T> il) : data(make_shared(vector<T>(il))) {
}
template <typename T>
T& Blob<T>::operator[](size_type t){
check(t, "out of range");
return ( *data)[t];
}
template <typename T>
void Blob<T>::pop_back() {
data->pop_back();
}
template <typename T>
class BlobPtr {
public:
BlobPtr():curr(0){}
BlobPtr(Blob<T>&a, size_t sz = 0): wptr(a.data),curr(sz){}
T& operator*()const{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
BlobPtr& operator++();
BlobPtr& operator--();
private:
shared_ptr<vector<T>> check(size_t, const string& )const;
weak_ptr<vector<T>> wptr;
size_t curr;
};
template <typename T>
BlobPtr& BlobPtr<T>::operator++(int){
BlobPtr ret = *this;
++*this;
return ret;
}
16.13
使用前置声明版本的==重载运算符
16.14
template <typename T>
class Screen {
typedef T pos;
friend istream& operator>>(istream& is, Screen<T> s);
friend ostream& operator<<(ostream& is, Screen<T> s);
public:
friend class Window_mgr;
Screen() = default;
Screen(pos wightVal, pos heightVal) :wight(wightVal), height(heightVal), contents(wightVal*heightVal, ' ') {
}
Screen(pos wightVal, pos heightVal, char contents) :wight(wightVal), height(heightVal), contents(wightVal*heightVal, contents) {
}
Screen& set(char);
Screen& move(pos r, pos col);
Screen& display(ostream& os);
int getWight()const { return wight; }
string& getContents() { return contents; }
int getHeight()const { return height; }
pos size()const;
private:
pos cursor;
pos wight, height;
string contents;
void do_displayer(ostream& os) {
os << contents;
}
};
template <typename T>
istream& operator>>(istream& is, Screen<T> s){
T tmpH, tmpW;
if(is>> tmpH >> tmpW){
s = Sreen(tmpH, tmpW);
}
return is;
}
template <typename T>
ostream& operator<<(ostream& os, Screen<T> s){
os << s.getWight() << " " << s.getHeight() << endl;
return os;
}
template <typename T>
T Screen<T>::size()const {
return height * wight;
}
class Window_mgr {
public:
typedef string::size_type ScreenIndex;
void clear(ScreenIndex index);
private:
vector<Screen<int>> screens{ Screen<int>(24, 80, ' ') };
};
void Window_mgr::clear(ScreenIndex index) {
Screen<int> & s = screens[index];
s.getContents() = string(s.getWight()*s.getHeight(), ' ');
}
template <typename T>
Screen<T>& Screen<T>::set(char c) {
contents[cursor] = c;
return *this;
}
template <typename T>
Screen<T>& Screen<T>::move(pos r, pos col) {
cursor = wight * r + col;
return *this;
}
template <typename T>
Screen<T>& Screen<T>::display(ostream& os) {
do_displayer(os);
return *this;
}
16.15
friend istream& operator>>(istream& is, Screen<T> s);
friend ostream& operator<<(ostream& is, Screen<T> s);
template <typename T>
istream& operator>>(istream& is, Screen<T> s) {
T tmpH, tmpW;
if (is >> tmpH >> tmpW) {
s = Sreen(tmpH, tmpW);
}
return is;
}
template <typename T>
ostream& operator<<(ostream& os, Screen<T> s) {
os << s.getWight() << " " << s.getHeight() << endl;
return os;
}
16.16
template <typename T>
class Vec {
friend bool operator==(const Vec& sv_0, const Vec& sv_1);
friend bool operator!=(const Vec& sv_0, const Vec& sv_1);
friend bool operator<(const Vec& sv_0, const Vec& sv_1);
public:
Vec() :emlemnts(nullptr), first_free(nullptr), cap(nullptr) {}
Vec(const Vec&);
Vec(Vec&& s) :emlemnts(std::move(s.emlemnts)), first_free(std::move(s.first_free)), cap(std::move(s.cap)) {
s.emlemnts = s.first_free = s.cap = nullptr;
};
Vec(initializer_list<T>);
const T& operator[](size_t n)const {
return emlemnts[n];
};
T& operator[](size_t n) {
return emlemnts[n];
};
Vec& operator=(Vec&);
Vec& operator=(initializer_list<T>);
Vec& operator=(Vec&&s) {
if (this != &s) {
free();
this->emlemnts = s.emlemnts;
this->first_free = s.first_free;
this->cap = s.cap;
s.emlemnts = s.first_free = s.cap = nullptr;
}
return *this;
};
~Vec();
void push_back(const T&);
T* begin()const { return emlemnts; }
T* end()const { return first_free; }
size_t size() { return first_free - emlemnts; };
size_t capacity() { return cap - emlemnts; };
void reserve(const size_t& n);
void resize(const size_t& n);
private:
T * emlemnts;
T* first_free;
T* cap;
allocator<T> alloc;
pair<T*, T* > alloc_n_copy(const T *, const T *);
void chk_n_alloc() { if (size() == capacity()) { reallocate(); } }
void reallocate();
void free();
};
template <typename T>
bool operator==(const Vec<T>& sv_0, const Vec<T>& sv_1) {
return (sv_0.emlemnts == sv_1.emlemnts) && (sv_0.first_free == sv_1.first_free) && (sv_0.cap == sv_1.cap);
}
template <typename T>
bool operator!=(const Vec<T>& sv_0, const Vec<T>& sv_1) {
return !(sv_0 == sv_1);
}
template <typename T>
bool operator<(const Vec<T>& sv_0, const Vec<T>& sv_1) {
size_t size_0 = sv_0.first_free - sv_0.emlemnts;
size_t size_1 = sv_1.first_free - sv_1.emlemnts;
if (size_0 != size_1) {
return size_0 < size_1;
}
for (size_t i = 0; i < size_0; i++) {
if ((*sv_0.emlemnts) != (*sv_1.emlemnts)) {
return (*sv_0.emlemnts) < (*sv_1.emlemnts);
}
}
return false;
}
template <typename T>
pair<T*, T* > Vec<T>::alloc_n_copy(const T * b, const T *e) {
auto data = alloc.allocate(e - b);
return { data, uninitialized_copy(b,e,data) };
}
template <typename T>
Vec<T>::~Vec() {
free();
}
template <typename T>
void Vec<T>::push_back(const T& s) {
chk_n_alloc();
alloc.construct(first_free++, s);
}
template <typename T>
Vec<T>::Vec(const Vec<T>& s) {
auto tmpAlloc = alloc_n_copy(s.begin(), s.end());
emlemnts = tmpAlloc.first;
emlemnts = tmpAlloc.second;
}
template <typename T>
Vec<T>::Vec(initializer_list<T> list) {
for (initializer_list<T>::iterator it = list.begin(); it != list.end(); it++) {
push_back(*it);
}
}
template <typename T>
Vec<T>& Vec<T>::operator=(initializer_list<T> list) {
for (initializer_list<T>::iterator it = list.begin(); it != list.end(); it++) {
push_back(*it);
}
return *this;
}
template <typename T>
Vec<T>& Vec<T>::operator=(Vec& s) {
auto tmpAlloc = alloc_n_copy(s.begin(), s.end());
free();
emlemnts = tmpAlloc.first;
first_free = tmpAlloc.second;
return *this;
}
template <typename T>
void Vec<T>::free() {
//for (auto p = first_free; p != emlemnts;) {
// alloc.destroy(--p);
//}
for_each(emlemnts, first_free, [](T& a) {a.~T(); });
alloc.deallocate(emlemnts, capacity());
}
template <typename T>
void Vec<T>::reallocate() {
auto newcapacity = size() ? 2 * size() : 1;
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;
auto elem = emlemnts;
for (size_t i = 0; i != size(); i++)
alloc.construct(dest++, move(*elem++));
free();
emlemnts = newdata;
first_free = dest;
cap = emlemnts + newcapacity;
}
template <typename T>
void Vec<T>::reserve(const size_t& n) {
if (n < size()) {
return;
}
auto newdata = alloc.allocate(n);
auto dest = newdata;
auto elem = emlemnts;
for (size_t i = 0; i != size(); i++)
alloc.construct(dest++, move(*elem++));
free();
emlemnts = newdata;
first_free = dest;
cap = emlemnts + n;
}
template <typename T>
void Vec<T>::resize(const size_t& n) {
auto newdata = alloc.allocate(n);
auto dest = newdata;
auto elem = emlemnts;
for (size_t i = 0; i != size() && i < n; i++)
alloc.construct(dest++, move(*elem++));
free();
emlemnts = newdata;
first_free = dest;
cap = emlemnts + n;
}