16.9 函数模板是可以实例化出特定函数的模板,类模板是可以实例化出特定类的模板。
16.10 当类模板被实例化时,编译器会根据提供的模板实参列表来绑定模板参数,替换类模板定义中模板参数出现的地方,这样就实例化出一个特定的类。
16.11 类模板的名字不是类型,只有实例化后才能形成类型。在class List代码中不能直接使用ListItem,应该使用ListItem<elemType>;在类模板作用域中,可以不提供实参,因此class List代码中可以用List代替List<elemType>。
16.12 Blob和BlobPtr模板代码:
#ifndef BLOB_H
#define BLOB_H
#include <iostream>
#include <vector>
#include <stdexcept>
#include <memory>
using namespace std;
template <typename> class BlobPtr;
template <typename T> class Blob {
friend class BlobPtr<T>;
public:
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(T &&t) { data->push_back(std::move(t)); }
void pop_back();
BlobPtr<T> begin() { return BlobPtr<T>(*this); }
BlobPtr<T> end()
{
auto ret = BlobPtr<T>(*this, data->size());
return ret;
}
T& front();
T& back();
T& operator[](size_type i);
const T& front() const;
const T& back() const;
const T& operator[](size_type i) const;
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>
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>
void Blob<T>::pop_back()
{
check(0, "pop back on empty Blob");
data->pop_back();
}
template <typename T>
T& Blob<T>::front()
{
check(0, "front on empty Blob");
return data->front();
}
template <typename T>
T& Blob<T>::back()
{
check(0, "back on empty Blob");
return data->back();
}
template <typename T>
T& Blob<T>::operator[](size_type i)
{
check(i, "subscritpt out of range");
return (*data)[i];
}
template <typename T>
const T& Blob<T>::front() const
{
check(0, "front on empty Blob");
return data->front();
}
template <typename T>
const T& Blob<T>::back() const
{
check(0, "back on empty Blob");
return data->back();
}
template <typename T>
const T& Blob<T>::operator[](size_type i) const
{
check(i, "subscritpt out of range");
return (*data)[i];
}
template <typename T>
bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> class BlobPtr {
friend bool
operator==<T>(const BlobPtr<T>&, const BlobPtr<T>&);
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--();
BlobPtr operator++(int);
BlobPtr operator--(int);
private:
shared_ptr<vector<T>> check(size_t, const string&) const;
weak_ptr<vector<T>> wptr;
size_t curr;
};
template <typename T>
shared_ptr<vector<T>>
BlobPtr<T>::check(size_t i, const string &msg) const
{
auto ret = wptr.lock();
if (!ret)
throw runtime_error("unbound BlobPtr");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator++()
{
check(curr, "increment past end of BlobPtr");
++curr;
return *this;
}
template <typename T>
BlobPtr<T>& BlobPtr<T>::operator--()
{
--curr;
check(-1, "decrement past begin of BlobPtr");
return *this;
}
template <typename T>
BlobPtr<T> BlobPtr<T>::operator++(int)
{
BlobPtr ret = *this;
++*this;
return ret;
}
template <typename T>
BlobPtr<T> BlobPtr<T>::operator--(int)
{
BlobPtr ret = *this;
--*this;
return ret;
}
template <typename T>
bool operator==(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
return lhs.wptr.lock().get() == rhs.wptr.lock().get() &&
lhs.curr == rhs.curr;
}
template <typename T>
bool operator!=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
return !(lhs == rhs);
}
#endif
16.13 选择一对一友好关系。
16.14 Screen类模板代码:
#ifndef SCREEN_H
#define SCREEN_H
#include <iostream>
using namespace std;
template <int H, int W> class Screen {
public:
typedef string::size_type pos;
Screen(): contents(H * W, ' ') { }
Screen(char c): contents(H * W, c) { }
char get() const { return contents[cursor]; }
inline char get(pos, pos) const;
Screen &move(pos r, pos c);
Screen &set(char);
Screen &display(ostream &os) {
do_display(os);
return *this;
}
const Screen &display(ostream &os) const {
do_display(os);
return *this;
}
private:
pos cursor = 0;
string contents;
void do_display(ostream &os) const { os << contents; }
};
template <int H, int W>
inline Screen<H, W> &Screen<H, W>::set(char c)
{
contents[cursor] = c;
return *this;
}
template <int H, int W>
inline Screen<H, W> &Screen<H, W>::move(pos r, pos c)
{
cursor = r * W + c;
return *this;
}
16.15 添加输入输出运算符:
#ifndef SCREEN_H
#define SCREEN_H
#include <iostream>
using namespace std;
template <int H, int W> class Screen;
template <int H, int W>
istream &operator>>(istream&, Screen<H, W>&);
template <int H, int W>
ostream &operator<<(ostream&, Screen<H, W>&);
template <int H, int W> class Screen {
friend istream &operator>> <H, W>(istream&, Screen<H, W>&);
friend ostream &operator<< <H, W>(ostream&, Screen<H, W>&);
...
};
template <int H, int W>
istream &operator>>(istream &is, Screen<H, W> &s)
{
string t;
is >> t;
s.contents = t.substr(0, H * W);
return is;
}
template <int H, int W>
ostream &operator<<(ostream &os, Screen<H, W> &s)
{
os << s.contents;
return os;
}
#endif
16.16 Vec.h文件定义Vec模板:
#ifndef VEC_H
#define VEC_H
#include <memory>
using namespace std;
template <typename T> class Vec {
public:
Vec(): elements(nullptr), first_free(nullptr), cap(nullptr) { }
Vec(const Vec&);
Vec(const T*, const T*);
Vec(initializer_list<T> lst);
Vec& operator=(const Vec&);
~Vec();
void push_back(const T&);
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) { if (n > capacity()) resize(n); }
void resize(size_t);
T& operator[](size_t n) { return elements[n]; }
private:
static allocator<T> alloc;
void chk_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;
};
template <typename T> std::allocator<T> Vec<T>::alloc;
template <typename T>
void Vec<T>::push_back(const T &s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
}
template <typename T>
pair<T*, T*> Vec<T>::alloc_n_copy(const T *b, const T *e)
{
T *data = alloc.allocate(e - b);
return make_pair(data, uninitialized_copy(b, e, data));
}
template <typename T>
void Vec<T>::free()
{
if (elements) {
for (auto p = first_free; p != elements; )
alloc.destroy(--p);
alloc.deallocate(elements, cap - elements);
}
}
template <typename T>
Vec<T>::Vec(const Vec<T> &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = newdata.second;
cap = newdata.second;
}
template <typename T>
Vec<T>::Vec(const T *b, const T *e)
{
// call alloc_n_copy to allocate exactly as many elements as in il
pair<T*, T*> newdata = alloc_n_copy(b, e);
elements = newdata.first;
first_free = cap = newdata.second;
}
template <typename T>
Vec<T>::Vec(initializer_list<T> lst)
{
auto newdata = alloc_n_copy(lst.begin(), lst.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
template <typename T>
Vec<T>::~Vec() { free(); }
template <typename T>
Vec<T> &Vec<T>::operator=(const Vec &rhs)
{
auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = newdata.first;
first_free = newdata.second;
cap = newdata.second;
return *this;
}
template <typename T>
void Vec<T>::reallocate()
{
auto newcapacity = size()? size() * 2 : 1;
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;
auto elem = elements;
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free();
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
template <typename T>
void Vec<T>::resize(size_t n)
{
if (n > size()) {
while ( n > size() )
push_back("");
} else if ( n < size() ){
while (size() > n )
alloc.destroy(--first_free);
}
}
#endif
本文介绍了C++中的函数模板和类模板,讲解了类模板在实例化过程中如何绑定模板参数,以及类模板名字与类型的区别。内容涉及Blob和BlobPtr模板的使用,以及Screen类模板的实现,还包括Vec模板的定义,并讨论了一对一友好关系和自定义输入输出运算符的添加。
33万+

被折叠的 条评论
为什么被折叠?



