练习 16.1:
编译器处理过程,用实际的模板实参来生成模板的一个特殊实例,其中参数被替换为对应的实参。
练习 16.2:
#include<iostream>
#include<functional>
#include<cstring>
using namespace std;
template<typename T>
int compare(const T& v1, const T& v2)
{
if (less<T>()(v1, v2))
return -1;
if (less<T>()(v2, v1))
return 1;
return 0;
}
template<unsigned N, unsigned M>
int compare(const char(&p1)[N], const char(&p2)[M])
{
return strcmp(p1, p2);
}
int main()
{
cout << compare(1, 0) << endl;
cout << compare("hi", "mom") << endl;
return 0;
}
练习 16.3:
二进制"<":"const_Ty"未定义此运算符或转换为预定义运算符可接受的类型。
练习 16.4:
#include<iostream>
#include<vector>
#include<list>
using namespace std;
template<typename Ty_iter, typename T>
Ty_iter Find(Ty_iter beg, Ty_iter end, const T& val)
{
for (; beg != end; ++beg)
{
if (*beg == val)
return beg;
}
return end;
}
int main()
{
vector<string> vec = { "Cpp", "Java", "Python", "Golang" };
list<string> lst = { "Cpp", "Java", "Python", "Golang" };
auto vec_pos = Find(vec.cbegin(), vec.cend(), "Python");
cout << boolalpha << (vec_pos != vec.end()) << endl;
auto lst_pos = Find(lst.begin(), lst.end(), "C");
cout << boolalpha << (lst_pos != lst.end()) << endl;
return 0;
}
练习 16.5:
#include<iostream>
using namespace std;
template<typename T, unsigned N>
void print(const T(&arr)[N])
{
for (const auto& elem : arr)
cout << elem << " ";
cout << endl;
}
int main()
{
string str[] = { "Cpp", "Java", "Python", "Golang" };
print(str);
return 0;
}
练习 16.6:
#include<iostream>
using namespace std;
template<typename T, unsigned N>
T* Begin(T(&arr)[N])
{
return arr;
}
template<typename T, unsigned N>
T* End(T(&arr)[N])
{
return arr + N;
}
int main()
{
string str[] = { "Cpp", "Java", "Python", "Golang" };
cout << *Begin(str) << " " << *(End(str)-1) << endl;
return 0;
}
练习 16.7:
#include<iostream>
using namespace std;
template<typename T, unsigned N>
constexpr unsigned Size(T(&arr)[N])
{
return N;
}
int main()
{
string str[] = { "Cpp", "Java", "Python", "Golang" };
cout << Size(str) << endl;
return 0;
}
练习 16.8:
所有标准库容器的迭代器都定义了==和!=,但是它们中的大多数都没有定义<操作符。通过例行地使用迭代器和!=,我们不必在意正在使用的容器类型。
练习 16.9:
- 函数模板: 用于实例化特定函数的定义。
- 类模板: 用于实例化特定类的定义。与函数模板的不同之处是,编译器不能为类模板推断模板参数类型。我们必须在模板名后的尖括号中提供模板实参列表来代替模板参数。
练习 16.10:
编译器重写类模板,用给定的模板实参替换模板形参的每个实例。
练习 16.11:
template <typename elemType> class ListItem;
template <typename elemType> class List {
public:
List<elemType>();
List<elemType>(const List<elemType> &);
List<elemType>& operator=(const List<elemType> &);
~List();
void insert(ListItem *ptr, elemType value); // 1
private:
ListItem *front, *end; // 2
};
// 使用类模板ListItem需要模板参数
void insert(ListItem<elemType> *ptr, elemType value);
ListItem<elemType> *front, *end;
练习 16.12:
#ifndef BLOB_H
#define BLOB_H
#include<vector>
#include<string>
#include<initializer_list>
#include<memory>
#include<algorithm>
#include<stdexcept>
using namespace std;
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> class ConstBlobPtr;
// Blob类
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator!=(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator<(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator>(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator<=(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator>=(const Blob<T>&, const Blob<T>&);
template<typename T> class Blob
{
friend class BlobPtr<T>;
friend class ConstBlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
friend bool operator!=<T>(const Blob<T>&, const Blob<T>&);
friend bool operator< <T>(const Blob<T>&, const Blob<T>&);
friend bool operator> <T>(const Blob<T>&, const Blob<T>&);
friend bool operator<=<T>(const Blob<T>&, const Blob<T>&);
friend bool operator>=<T>(const Blob<T>&, const Blob<T>&);
public:
typedef typename vector<T>::size_type size_type;
// 构造函数
Blob():data(make_shared<vector<T>>()) {}
Blob(initializer_list<T> il):data(make_shared<vector<T>>(il)) {}
Blob(const Blob<T>& rhs):data(make_shared<vector<T>>(*rhs.data)){}
Blob& operator=(const Blob<T>& rhs)
{
data = make_shared<vector<T>>(*rhs.data);
return *this;
}
Blob(Blob<T>&& rhs)noexcept:data(std::move(rhs.data)){}
Blob& operator=(Blob<T>&& rhs)noexcept
{
if (*this != rhs)
{
data = std::move(rhs.data);
rhs = nullptr;
}
return *this;
}
// Blob中的元素数目
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();
// 元素访问
T& front();
const T& front()const;
T& back();
const T& back()const;
T& operator[](size_type i);
const T& operator[](size_type i)const;
BlobPtr<T> begin();
BlobPtr<T> end();
ConstBlobPtr<T> cbegin() const;
ConstBlobPtr<T> cend() const;
private:
shared_ptr<vector<T>> data;
// data[i]无效,则抛出msg
void check(size_type i, const string& msg)const;
};
// Blob友元函数
template<typename T> bool operator==(const Blob<T>& lhs, const Blob<T>& rhs)
{
return *lhs.data == *rhs.data;
}
template<typename T> bool operator!=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T> bool operator<(const Blob<T>& lhs, const Blob<T>& rhs)
{
return lexicographical_compare(lhs.data->begin(), lhs.data->end(),
rhs.data->begin(), rhs.data->end());
}
template<typename T> bool operator>(const Blob<T>& lhs, const Blob<T>& rhs)
{
return rhs < lhs;
}
template<typename T> bool operator<=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(rhs < lhs);
}
template<typename T> bool operator>=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(lhs < rhs);
}
// Blob成员函数
template<typename T>
inline void Blob<T>::check(size_type i, const string& msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
template<typename T>
inline void Blob<T>::pop_back()
{
check(0, "pop_back on empty Blob");
data->pop_back();
}
template<typename T>
inline T& Blob<T>::front()
{
check(0, "front on empty Blob");
data->front();
}
template<typename T>
inline const T& Blob<T>::front()const
{
check(0, "front on empty Blob");
data->front();
}
template<typename T>
inline T& Blob<T>::back()
{
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
inline const T& Blob<T>::back()const
{
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
inline T& Blob<T>::operator[](size_type i)
{
check(i, "subscript out of range");
return (*data)[i];
}
template<typename T>
inline const T& Blob<T>::operator[](size_type i)const
{
check(i, "subscript out of range");
return (*data)[i];
}
template<typename T>
inline BlobPtr<T> Blob<T>::begin()
{
return BlobPtr<T>(*this);
}
template<typename T>
inline BlobPtr<T> Blob<T>::end()
{
return BlobPtr<T>(*this, data->size());
}
template<typename T>
inline ConstBlobPtr<T> Blob<T>::cbegin()const
{
return ConstBlobPtr<T>(*this);
}
template<typename T>
inline ConstBlobPtr<T> Blob<T>::cend()const
{
return ConstBlobPtr<T>(*this, data->size());
}
// BlobPtr类
template <typename T> bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator!=(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator>(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<=(const BlobPtr<T>&, const BlobPtr<T>&);
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>&);
friend bool operator!=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator< <T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator> <T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator<=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
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;
T* operator->()const;
T& operator[](size_t);
const T& operator[](size_t)const;
BlobPtr& operator++();
BlobPtr& operator--();
BlobPtr operator++(int);
BlobPtr operator--(int);
BlobPtr& operator+=(size_t);
BlobPtr& operator-=(size_t);
BlobPtr operator+(size_t)const;
BlobPtr operator-(size_t)const;
private:
// 若检查成功,check返回一个指向vector的shared_ptr
shared_ptr<vector<T>> check(size_t, const string&)const;
// 保存一个weak_ptr,表示底层vector可能被销毁
weak_ptr<vector<T>> wptr;
size_t curr; // 数组当前位置
};
// BlobPtr友元函数
template<typename T>
bool operator==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr == lhs.curr;
}
template<typename T>
bool operator!=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr < lhs.curr;
}
template<typename T>
bool operator>(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr > lhs.curr;
}
template<typename T>
bool operator<=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr <= rhs.curr;
}
template<typename T>
bool operator>=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr >= rhs.curr;
}
// BlobPtr成员函数
template<typename T>
inline shared_ptr<vector<T>> BlobPtr<T>::check(size_t i, const string& msg)const
{
auto ret = wptr.lock(); // vector<T>是否还存在
if (!ret)
throw runtime_error("unbound Blob");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
template<typename T>
inline T& BlobPtr<T>::operator*()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
template<typename T>
inline T* BlobPtr<T>::operator->()const
{ // 将实际工作委托给解引用运算符
return &this->operator*();
}
template<typename T>
inline T& BlobPtr<T>::operator[](size_t n)
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline const T& BlobPtr<T>::operator[](size_t n)const
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator++()
{
check(curr, "increment past end");
++curr;
return *this;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator--()
{
--curr;
check(curr, "decrement past begin");
return *this;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator++(int)
{
BlobPtr ret = *this;
++*this; // 推进一个元素,前置++检查递增是否合法
return ret;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator--(int)
{
BlobPtr ret = *this;
--*this;
return ret;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator+=(size_t n)
{
curr += n;
check(n, "increment past end of BlobPtr");
return *this;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator-=(size_t n)
{
curr -= n;
check(n, "decrement past begin of BlobPtr");
return *this;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator+(size_t n)const
{
BlobPtr ret = *this;
ret += n;
return ret;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator-(size_t n)const
{
BlobPtr ret = *this;
ret -= n;
return ret;
}
// ConstBlobPtr类
template <typename T> bool operator==(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator!=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator<(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator<=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator>=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template<typename T> class ConstBlobPtr
{
friend bool operator==<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator!=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator< <T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator> <T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator<=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator>=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
public:
ConstBlobPtr() : curr(0) {}
ConstBlobPtr(const Blob<T>& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
const T& operator*()const;
const T* operator->()const;
const T& operator[](size_t)const;
ConstBlobPtr& operator++();
ConstBlobPtr& operator--();
ConstBlobPtr operator++(int);
ConstBlobPtr operator--(int);
ConstBlobPtr& operator+=(size_t);
ConstBlobPtr& operator-=(size_t);
ConstBlobPtr operator+(size_t)const;
ConstBlobPtr operator-(size_t)const;
private:
// 若检查成功,check返回一个指向vector的shared_ptr
shared_ptr<vector<T>> check(size_t, const string&)const;
// 保存一个weak_ptr,表示底层vector可能被销毁
weak_ptr<vector<T>> wptr;
size_t curr; // 数组当前位置
};
// ConstBlobPtr友元函数
template<typename T>
bool operator==(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr == rhs.curr;
}
template<typename T>
bool operator!=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr < lhs.curr;
}
template<typename T>
bool operator>(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr > lhs.curr;
}
template<typename T>
bool operator<=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr <= rhs.curr;
}
template<typename T>
bool operator>=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr >= rhs.curr;
}
// ConstBlobPtr成员函数
template<typename T>
inline shared_ptr<vector<T>> ConstBlobPtr<T>::check(size_t i, const string& msg)const
{
auto ret = wptr.lock(); // vector<T>是否还存在
if (!ret)
throw runtime_error("unbound Blob");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
template<typename T>
inline const T& ConstBlobPtr<T>::operator*()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
template<typename T>
inline const T* ConstBlobPtr<T>::operator->()const
{ // 将实际工作委托给解引用运算符
return &this->operator*();
}
template<typename T>
inline const T& ConstBlobPtr<T>::operator[](size_t n)const
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator++()
{
check(curr, "increment past end");
++curr;
return *this;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator--()
{
--curr;
check(curr, "decrement past begin");
return *this;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator++(int)
{
ConstBlobPtr ret = *this;
++* this; // 推进一个元素,前置++检查递增是否合法
return ret;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator--(int)
{
ConstBlobPtr ret = *this;
--* this;
return ret;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator+=(size_t n)
{
curr += n;
check(n, "increment past end of BlobPtr");
return *this;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator-=(size_t n)
{
curr -= n;
check(n, "decrement past begin of BlobPtr");
return *this;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator+(size_t n)const
{
ConstBlobPtr ret = *this;
ret += n;
return ret;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator-(size_t n)const
{
ConstBlobPtr ret = *this;
ret -= n;
return ret;
}
#endif
练习 16.13:
建立对应实例及其友元间的友好关系。
练习 16.14 && 16.15:
#ifndef SCREEN_H
#define SCREEN_H
#include<iostream>
#include<string>
using namespace std;
using pos = string::size_type;
template<pos H, pos W> class Screen;
template<pos H, pos W> istream& operator>>(istream&, Screen<H, W>&);
template<pos H, pos W> ostream& operator<<(ostream&, Screen<H, W>&);
template<pos H, pos W> class Screen
{
friend istream& operator>><H, W>(istream&, Screen<H, W>&);
friend ostream& operator<<<H, W>(ostream&, Screen<H, W>&);
public:
// 构造函数
Screen() = default;
Screen(char c) : contents(H* W, c) {}
// 成员函数
char get() const { return contents[cursor]; } // 获取光标处的字符
char get(pos r, pos c) const { return contents[r * W + c]; }
Screen& move(pos r, pos c);
Screen& set(char ch);
Screen& set(pos r, pos c, char ch);
const Screen& display(ostream& os) const
{
do_display(os);
return *this;
}
Screen& display(ostream& os)
{
do_display(os);
return *this;
}
private:
void do_display(ostream& os) const { os << contents; }
pos cursor = 0;
string contents;
};
// 友元函数
template<pos H, pos W> istream& operator>>(istream& is, Screen<H, W>& s)
{
string input;
is >> input;
for (auto c : input)
{
s.set(c);
++s.cursor;
}
return is;
}
template<pos H, pos W> ostream& operator<<(ostream& os, Screen<H, W>& s)
{
for (pos r = 0; r != H; ++r)
{
for (pos c = 0; c != W; ++c)
{
os << s.get(r, c);
}
os << endl;
}
return os;
}
// 成员函数
template<pos H, pos W>
inline Screen<H, W>& Screen<H, W>::move(pos r, pos c)
{
cursor = r * W + c;
return *this;
}
template<pos H, pos W>
inline Screen<H, W>& Screen<H, W>::set(char ch)
{
contents[cursor] = ch;
return *this;
}
template<pos H, pos W>
inline Screen<H, W>& Screen<H, W>::set(pos r, pos c, char ch)
{
contents[r * W + c] = ch;
return *this;
}
#endif
练习 16.16:
#ifndef VEC_H
#define VEC_H
#include<initializer_list>
#include<memory>
#include<algorithm>
using namespace std;
template<typename T> class Vec;
template<typename T> bool operator==(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator!=(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator<(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator>(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator<=(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator>=(const Vec<T>&, const Vec<T>&);
template<typename T> class Vec
{
friend bool operator==<T>(const Vec<T>&, const Vec<T>&);
friend bool operator!=<T>(const Vec<T>&, const Vec<T>&);
friend bool operator< <T>(const Vec<T>&, const Vec<T>&);
friend bool operator> <T>(const Vec<T>&, const Vec<T>&);
friend bool operator<=<T>(const Vec<T>&, const Vec<T>&);
friend bool operator>=<T>(const Vec<T>&, const Vec<T>&);
public:
Vec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
Vec(initializer_list<T>);
Vec(const Vec<T>&);
Vec& operator=(const Vec<T>&);
Vec(Vec<T>&&)noexcept;
Vec& operator=(Vec<T>&&)noexcept;
~Vec();
T* begin()const { return elements; }
T* end()const { return first_free; }
void push_back(const T&);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
T& at(size_t n) { return *(elements + n); }
const T& at(size_t n)const { return *(elements + n); }
T& operator[](size_t n) { return elements[n]; }
const T& operator[](size_t n)const { return elements[n]; }
void reserve(size_t new_cap);
void resize(size_t n);
void resize(size_t n, const T&);
private:
// 工具函数-拷贝控制
pair<T*, T*> alloc_n_copy(const T*, const T*);
void range_initialize(const T*, const T*);
void free();
// 工具函数-分配内存移动元素
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
void reallocate();
void alloc_n_move(size_t new_cap);
private:
T* elements;
T* first_free;
T* cap;
allocator<T> alloc;
};
// 拷贝控制工具函数
template<typename T>
pair<T*, T*> Vec<T>::alloc_n_copy(const T* beg, const T* end)
{
auto pbeg = alloc.allocate(end - beg);
auto pend = uninitialized_copy(beg, end, pbeg);
return pair<T*, T*>(pbeg, pend);
}
template<typename T>
void Vec<T>::range_initialize(const T* beg, const T* end)
{
auto data = alloc_n_copy(beg, end);
elements = data.first;
first_free = cap = data.second;
}
template<typename T>
void Vec<T>::free()
{
if (elements)
{
for_each(elements, first_free,
[this](T& obj) {alloc.destroy(&obj); });
alloc.deallocate(elements, cap - elements);
}
}
// 拷贝控制函数
template<typename T>
Vec<T>::Vec(initializer_list<T> il)
{
range_initialize(il.begin(), il.end());
}
template<typename T>
Vec<T>::Vec(const Vec<T>& rhs)
{
range_initialize(rhs.begin(), rhs.end());
}
template<typename T>
Vec<T>& Vec<T>::operator=(const Vec<T>& rhs)
{
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
template<typename T>
Vec<T>::Vec(Vec<T>&& rhs)noexcept :
elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
template<typename T>
Vec<T>& Vec<T>::operator=(Vec<T>&& rhs)noexcept
{
if (*this != rhs)
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
template<typename T>
Vec<T>::~Vec()
{
free();
}
// 工具函数-分配内存移动元素
template<typename T>
void Vec<T>::alloc_n_move(size_t new_cap)
{
auto newdata = alloc.allocate(new_cap);
auto dest = newdata;
for (auto beg = elements; beg != first_free; ++beg)
alloc.construct(dest++, std::move(*beg));
free();
elements = newdata;
first_free = dest;
cap = newdata + new_cap;
}
template<typename T>
void Vec<T>::reallocate()
{
auto new_cap = size() ? 2 * size() : 1;
alloc_n_move(new_cap);
}
// 普通成员函数
template<typename T>
void Vec<T>::push_back(const T& t)
{
chk_n_alloc();
alloc.construct(first_free++, t);
}
template<typename T>
void Vec<T>::reserve(size_t new_cap)
{
if (new_cap <= capacity())
return;
alloc_n_move(new_cap);
}
template<typename T>
void Vec<T>::resize(size_t n)
{
resize(n, T());
}
template<typename T>
void Vec<T>::resize(size_t n, const T& t)
{
if (n > size())
{
if (n > capacity())
reserve(2 * n);
while (first_free != elements + n)
alloc.construct(first_free++, t);
}
else if (n < size())
{
while (first_free != elements + n)
alloc.destroy(--first_free);
}
}
// 友元函数
template<typename T>
bool operator==(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lhs.size() == rhs.size()
&& equal(lhs.begin(), lhs.begin(), rhs.begin());
}
template<typename T>
bool operator!=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.begin(),
rhs.begin(), rhs.end());
}
template<typename T>
bool operator>(const Vec<T>& lhs, const Vec<T>& rhs)
{
return (rhs < lhs);
}
template<typename T>
bool operator<=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(rhs < lhs);
}
template<typename T>
bool operator>=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(lhs < rhs);
}
#endif
练习 16.17:
当我们希望通知编译器一个名字表示一个类型时,必须使用关键字typename,而不是class。
练习 16.18:
template <typename T, U, typename V> void f1(T, U, V);// 非法,缺少关键字typename
template <typename T> T f2(int &T); // 非法,重用模板参数名
inline template <typename T> T foo(T, unsigned int*); // 非法,inline必须放在模板参数列表之后
template <typename T> f4(T, T); // 非法,无返回类型
typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a); // typename隐藏了typedef
修改:
template <typename T, typename U, typename V> void f1(T, U, V);
template <typename T> T f2(int &);
template <typename T> inline T foo(T, unsigned int*);
template <typename T> void f4(T, T);
typedef char Ctype;
template <typename T> T f5(Ctype a);
练习 16.19:
#include<iostream>
#include<vector>
using namespace std;
template<typename Container>
ostream& print(ostream& os, const Container& c)
{
using size_type = typename Container::size_type;
for (size_type i = 0; i != c.size(); ++i) // 可以使用auto
os << c[i] << " ";
return os;
}
int main()
{
vector<int> vec = { 0,1,2,3,4,5,6 };
print(cout, vec) << endl;
return 0;
}
练习 16.20:
#include<iostream>
#include<vector>
using namespace std;
template<typename Container>
ostream& print(ostream& os, const Container& c)
{
using IterType = typename Container::const_iterator;
for (IterType iter = c.cbegin(); iter != c.cend(); ++iter) // 可以使用auto
os << *iter << " ";
return os;
}
int main()
{
vector<int> vec = { 0,1,2,3,4,5,6 };
print(cout, vec) << endl;
return 0;
}
练习 16.21:
#include<iostream>
using namespace std;
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;
};
#include"DebugDelete.h"
#include<memory>
#include<string>
int main()
{
double* p = new double;
DebugDelete d;
d(p);
int* ip = new int;
DebugDelete()(ip);
unique_ptr<int, DebugDelete> up(new int, DebugDelete());
unique_ptr<string, DebugDelete> usp(new string, DebugDelete());
}
练习 16.22:
#include"DebugDelete.h"
#include<iostream>
#include<string>
#include<fstream>
#include<memory>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<algorithm>
using namespace std;
class QueryResult;
class TextQuery
{
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream&);
QueryResult query(const string&)const;
private:
shared_ptr<vector<string>> file;
map<string, shared_ptr<set<line_no>>> wm;
};
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
using line_no = vector<string>::size_type;
QueryResult(string s, shared_ptr<set<line_no>> plines,
shared_ptr<vector<string>> f) : sought(s), lines(plines), file(f) { }
private:
string sought;
shared_ptr<set<line_no>> lines;
shared_ptr<vector<string>> file;
};
TextQuery::TextQuery(ifstream& ifs) : file(new vector<string>)
{
line_no lineNo = 0;
for (string line; getline(ifs, line); ++lineNo)
{
file->push_back(line);
istringstream line_iss(line);
for (string word; line_iss >> word;)
{
auto punct_pos = find_if(word.begin(), word.end(), ispunct);
if (punct_pos != word.end())
word = string(word.begin(), punct_pos);
auto& lines = wm[word]; // 将lines绑定绑定到与word关联的shared_ptr<set>
if (!lines)
lines.reset(new set<line_no>, DebugDelete()); // 分配一个新的set
lines->insert(lineNo); // 将此行号插入set中
}
}
}
QueryResult TextQuery::query(const string& sought)const
{
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if (loc != wm.end())
return QueryResult(sought, loc->second, file);
else
return QueryResult(sought, nodata, file);
}
ostream& print(ostream& os, const QueryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size()
<< (qr.lines->size() > 1 ? " times" : " time") << endl;
for (auto line : *qr.lines)
os << "\t(line " << line + 1 << ") " << (*qr.file)[line] << endl;
return os;
}
void runQueries(ifstream& infile)
{
TextQuery tq(infile);
while (true)
{
cout << "enter word to look for, or \"q\" to quit: ";
string s;
if (cin >> s && s != "q")
print(cout, tq.query(s)) << endl;
else
break;
}
}
int main()
{
ifstream ifs("storyDataFile.txt");
runQueries(ifs);
return 0;
}
练习 16.24:
#ifndef BLOB_H
#define BLOB_H
#include<vector>
#include<string>
#include<initializer_list>
#include<memory>
#include<algorithm>
#include<stdexcept>
using namespace std;
template<typename T> class Blob;
template<typename T> class BlobPtr;
template<typename T> class ConstBlobPtr;
// Blob类
template<typename T> bool operator==(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator!=(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator<(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator>(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator<=(const Blob<T>&, const Blob<T>&);
template<typename T> bool operator>=(const Blob<T>&, const Blob<T>&);
template<typename T> class Blob
{
friend class BlobPtr<T>;
friend class ConstBlobPtr<T>;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
friend bool operator!=<T>(const Blob<T>&, const Blob<T>&);
friend bool operator< <T>(const Blob<T>&, const Blob<T>&);
friend bool operator> <T>(const Blob<T>&, const Blob<T>&);
friend bool operator<=<T>(const Blob<T>&, const Blob<T>&);
friend bool operator>=<T>(const Blob<T>&, const Blob<T>&);
public:
typedef typename vector<T>::size_type size_type;
// 构造函数
Blob():data(make_shared<vector<T>>()) {}
template<typename It> Blob(It b, It e): data(make_shared<vector<T>>(b, e)){}
Blob(initializer_list<T> il):data(make_shared<vector<T>>(il)) {}
Blob(const Blob<T>& rhs):data(make_shared<vector<T>>(*rhs.data)){}
Blob& operator=(const Blob<T>& rhs)
{
data = make_shared<vector<T>>(*rhs.data);
return *this;
}
Blob(Blob<T>&& rhs)noexcept:data(std::move(rhs.data)){}
Blob& operator=(Blob<T>&& rhs)noexcept
{
if (*this != rhs)
{
data = std::move(rhs.data);
rhs = nullptr;
}
return *this;
}
// Blob中的元素数目
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();
// 元素访问
T& front();
const T& front()const;
T& back();
const T& back()const;
T& operator[](size_type i);
const T& operator[](size_type i)const;
BlobPtr<T> begin();
BlobPtr<T> end();
ConstBlobPtr<T> cbegin() const;
ConstBlobPtr<T> cend() const;
private:
shared_ptr<vector<T>> data;
// data[i]无效,则抛出msg
void check(size_type i, const string& msg)const;
};
// Blob友元函数
template<typename T> bool operator==(const Blob<T>& lhs, const Blob<T>& rhs)
{
return *lhs.data == *rhs.data;
}
template<typename T> bool operator!=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T> bool operator<(const Blob<T>& lhs, const Blob<T>& rhs)
{
return lexicographical_compare(lhs.data->begin(), lhs.data->end(),
rhs.data->begin(), rhs.data->end());
}
template<typename T> bool operator>(const Blob<T>& lhs, const Blob<T>& rhs)
{
return rhs < lhs;
}
template<typename T> bool operator<=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(rhs < lhs);
}
template<typename T> bool operator>=(const Blob<T>& lhs, const Blob<T>& rhs)
{
return !(lhs < rhs);
}
// Blob成员函数
template<typename T>
inline void Blob<T>::check(size_type i, const string& msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
template<typename T>
inline void Blob<T>::pop_back()
{
check(0, "pop_back on empty Blob");
data->pop_back();
}
template<typename T>
inline T& Blob<T>::front()
{
check(0, "front on empty Blob");
data->front();
}
template<typename T>
inline const T& Blob<T>::front()const
{
check(0, "front on empty Blob");
data->front();
}
template<typename T>
inline T& Blob<T>::back()
{
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
inline const T& Blob<T>::back()const
{
check(0, "back on empty Blob");
return data->back();
}
template<typename T>
inline T& Blob<T>::operator[](size_type i)
{
check(i, "subscript out of range");
return (*data)[i];
}
template<typename T>
inline const T& Blob<T>::operator[](size_type i)const
{
check(i, "subscript out of range");
return (*data)[i];
}
template<typename T>
inline BlobPtr<T> Blob<T>::begin()
{
return BlobPtr<T>(*this);
}
template<typename T>
inline BlobPtr<T> Blob<T>::end()
{
return BlobPtr<T>(*this, data->size());
}
template<typename T>
inline ConstBlobPtr<T> Blob<T>::cbegin()const
{
return ConstBlobPtr<T>(*this);
}
template<typename T>
inline ConstBlobPtr<T> Blob<T>::cend()const
{
return ConstBlobPtr<T>(*this, data->size());
}
// BlobPtr类
template <typename T> bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator!=(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator>(const BlobPtr<T>&, const BlobPtr<T>&);
template <typename T> bool operator<=(const BlobPtr<T>&, const BlobPtr<T>&);
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>&);
friend bool operator!=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator< <T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator> <T>(const BlobPtr<T>&, const BlobPtr<T>&);
friend bool operator<=<T>(const BlobPtr<T>&, const BlobPtr<T>&);
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;
T* operator->()const;
T& operator[](size_t);
const T& operator[](size_t)const;
BlobPtr& operator++();
BlobPtr& operator--();
BlobPtr operator++(int);
BlobPtr operator--(int);
BlobPtr& operator+=(size_t);
BlobPtr& operator-=(size_t);
BlobPtr operator+(size_t)const;
BlobPtr operator-(size_t)const;
private:
// 若检查成功,check返回一个指向vector的shared_ptr
shared_ptr<vector<T>> check(size_t, const string&)const;
// 保存一个weak_ptr,表示底层vector可能被销毁
weak_ptr<vector<T>> wptr;
size_t curr; // 数组当前位置
};
// BlobPtr友元函数
template<typename T>
bool operator==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr == lhs.curr;
}
template<typename T>
bool operator!=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr < lhs.curr;
}
template<typename T>
bool operator>(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr > lhs.curr;
}
template<typename T>
bool operator<=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr <= rhs.curr;
}
template<typename T>
bool operator>=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs)
{
return lhs.curr >= rhs.curr;
}
// BlobPtr成员函数
template<typename T>
inline shared_ptr<vector<T>> BlobPtr<T>::check(size_t i, const string& msg)const
{
auto ret = wptr.lock(); // vector<T>是否还存在
if (!ret)
throw runtime_error("unbound Blob");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
template<typename T>
inline T& BlobPtr<T>::operator*()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
template<typename T>
inline T* BlobPtr<T>::operator->()const
{ // 将实际工作委托给解引用运算符
return &this->operator*();
}
template<typename T>
inline T& BlobPtr<T>::operator[](size_t n)
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline const T& BlobPtr<T>::operator[](size_t n)const
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator++()
{
check(curr, "increment past end");
++curr;
return *this;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator--()
{
--curr;
check(curr, "decrement past begin");
return *this;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator++(int)
{
BlobPtr ret = *this;
++*this; // 推进一个元素,前置++检查递增是否合法
return ret;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator--(int)
{
BlobPtr ret = *this;
--*this;
return ret;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator+=(size_t n)
{
curr += n;
check(n, "increment past end of BlobPtr");
return *this;
}
template<typename T>
inline BlobPtr<T>& BlobPtr<T>::operator-=(size_t n)
{
curr -= n;
check(n, "decrement past begin of BlobPtr");
return *this;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator+(size_t n)const
{
BlobPtr ret = *this;
ret += n;
return ret;
}
template<typename T>
inline BlobPtr<T> BlobPtr<T>::operator-(size_t n)const
{
BlobPtr ret = *this;
ret -= n;
return ret;
}
// ConstBlobPtr类
template <typename T> bool operator==(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator!=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator<(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator<=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template <typename T> bool operator>=(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
template<typename T> class ConstBlobPtr
{
friend bool operator==<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator!=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator< <T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator> <T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator<=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
friend bool operator>=<T>(const ConstBlobPtr<T>&, const ConstBlobPtr<T>&);
public:
ConstBlobPtr() : curr(0) {}
ConstBlobPtr(const Blob<T>& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
const T& operator*()const;
const T* operator->()const;
const T& operator[](size_t)const;
ConstBlobPtr& operator++();
ConstBlobPtr& operator--();
ConstBlobPtr operator++(int);
ConstBlobPtr operator--(int);
ConstBlobPtr& operator+=(size_t);
ConstBlobPtr& operator-=(size_t);
ConstBlobPtr operator+(size_t)const;
ConstBlobPtr operator-(size_t)const;
private:
// 若检查成功,check返回一个指向vector的shared_ptr
shared_ptr<vector<T>> check(size_t, const string&)const;
// 保存一个weak_ptr,表示底层vector可能被销毁
weak_ptr<vector<T>> wptr;
size_t curr; // 数组当前位置
};
// ConstBlobPtr友元函数
template<typename T>
bool operator==(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr == rhs.curr;
}
template<typename T>
bool operator!=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr < lhs.curr;
}
template<typename T>
bool operator>(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr > lhs.curr;
}
template<typename T>
bool operator<=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr <= rhs.curr;
}
template<typename T>
bool operator>=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs)
{
return lhs.curr >= rhs.curr;
}
// ConstBlobPtr成员函数
template<typename T>
inline shared_ptr<vector<T>> ConstBlobPtr<T>::check(size_t i, const string& msg)const
{
auto ret = wptr.lock(); // vector<T>是否还存在
if (!ret)
throw runtime_error("unbound Blob");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
template<typename T>
inline const T& ConstBlobPtr<T>::operator*()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
template<typename T>
inline const T* ConstBlobPtr<T>::operator->()const
{ // 将实际工作委托给解引用运算符
return &this->operator*();
}
template<typename T>
inline const T& ConstBlobPtr<T>::operator[](size_t n)const
{
auto p = check(n, "out of range");
return (*p)[n];
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator++()
{
check(curr, "increment past end");
++curr;
return *this;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator--()
{
--curr;
check(curr, "decrement past begin");
return *this;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator++(int)
{
ConstBlobPtr ret = *this;
++* this; // 推进一个元素,前置++检查递增是否合法
return ret;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator--(int)
{
ConstBlobPtr ret = *this;
--* this;
return ret;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator+=(size_t n)
{
curr += n;
check(n, "increment past end of BlobPtr");
return *this;
}
template<typename T>
inline ConstBlobPtr<T>& ConstBlobPtr<T>::operator-=(size_t n)
{
curr -= n;
check(n, "decrement past begin of BlobPtr");
return *this;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator+(size_t n)const
{
ConstBlobPtr ret = *this;
ret += n;
return ret;
}
template<typename T>
inline ConstBlobPtr<T> ConstBlobPtr<T>::operator-(size_t n)const
{
ConstBlobPtr ret = *this;
ret -= n;
return ret;
}
#endif
#include"Blob.h"
#include<iostream>
#include<list>
template<typename T>
ostream& print(Blob<T>& b, ostream& os = cout)
{
for (auto iter = b.cbegin(); iter != b.cend(); ++iter)
cout << *iter << " ";
return os;
}
int main()
{
int ia[] = { 0,1,2,3,4,5,6,7,8,9 };
vector<long> vi = { 0,1,2,3,4,5,6,7,8,9 };
list<const char*> w = { "now", "is", "the", "time" };
Blob<int> a1(begin(ia), end(ia));
Blob<int> a2(vi.begin(), vi.end());
Blob<string> a3(w.begin(), w.end());
print(a1) << endl;
print(a2) << endl;
print(a3) << endl;
return 0;
}
练习 16.25:
extern template class vector<string>;
// Vector<string>实例化声明在这里,它必须实例化在程序的其他地方。
template class vector<Sales_data>;
// vector<Sales_data>实例化该类的所有成员。
练习 16.26:
不可以,因为当我们显式实例化vector<Nodefault>时,编译器会实例化vector的所有成员函数,包括它接受容器大小参数的构造函数。vector的这个构造函数会使用元素类型的默认构造函数来对元素进行值初始化,而NoDefault没有默认构造函数,从而导致编译错误。
练习 16.27:
template <typename T> class Stack { };
void f1(Stack<char>); // (a) 没有实例化,函数在调用时被实例化。
class Exercise {
Stack<double> &rsd; // (b) 没有实例化,引用和指针不需要实例化
Stack<int> si; // (c) 实例化
};
int main() {
Stack<char> *sc; // (d) 没有实例化,引用和指针不需要实例化
f1(*sc); // (e) 实例化
int iObj = sizeof(Stack< string >); // (f) 实例化
}
练习 16.28:
#ifndef SHARED_PTR_H
#define SHARED_PTR_H
template<typename T> class Shared_ptr
{
using DelFuncPtr = void(*)(T*);
public:
Shared_ptr(T* ptr = nullptr, DelFuncPtr del = nullptr) :
ptr_(ptr), use_ptr_(new size_t(ptr != nullptr)), del_(del) {}
~Shared_ptr()
{
if (!ptr_)
return;
if (-- * use_ptr_ == 0)
{
del_ ? del_(ptr_) : delete ptr_;
delete use_ptr_;
}
ptr_ = nullptr;
use_ptr_ = nullptr;
}
Shared_ptr(const Shared_ptr& rhs) : ptr_(rhs.ptr_), use_ptr_(rhs.use_ptr_), del_(rhs.del_)
{
++* use_ptr_;
}
Shared_ptr& operator=(Shared_ptr rhs)
{
swap(rhs);
return *this;
}
Shared_ptr(Shared_ptr&& rhs)noexcept : ptr_(rhs.ptr_), use_ptr_(rhs.use_ptr_), del_(rhs.del_)
{
rhs.ptr_ = rhs.use_ptr_ = rhs.del_ = nullptr;
}
void swap(Shared_ptr& rhs)noexcept
{
using std::swap;
swap(ptr_, rhs.ptr_);
swap(use_ptr_, rhs.use_ptr_);
swap(del_, rhs.del_);
}
void reset(T* ptr = nullptr, DelFuncPtr del = nullptr)
{
Shared_ptr temp(ptr, del);
swap(temp);
}
T* get()const noexcept { return ptr_; }
T& operator*()const noexcept { return *ptr_; }
T* operator->()const noexcept { return ptr_; }
size_t use_count()const noexcept { return *use_ptr_; }
explicit operator bool()const noexcept { return ptr_ != nullptr; }
private:
T* ptr_ = nullptr;
size_t* use_ptr_ = nullptr;
DelFuncPtr del_ = nullptr;
};
#endif
#ifndef UNIQUE_PTR_H
#define UNIQUE_PTR_H
class Delete
{
public:
template<typename T> void operator()(T* ptr)const { delete ptr; }
};
template<typename T, typename D = Delete> class Unique_ptr
{
public:
Unique_ptr(T* ptr = nullptr, const D& d = D())noexcept : ptr_(ptr), deleter_(d) {}
~Unique_ptr() { deleter_(ptr_); }
Unique_ptr(const Unique_ptr&) = delete;
Unique_ptr& operator=(const Unique_ptr&) = delete;
Unique_ptr(Unique_ptr&& rhs)noexcept : ptr_(rhs.ptr_), deleter_(std::move(rhs.deleter_))
{
rhs.ptr_ = nullptr;
}
Unique_ptr& operator=(Unique_ptr&& rhs)noexcept
{
if (*this != rhs)
{
reset();
ptr_ = rhs.ptr_;
deleter_ = std::move(rhs.deleter_);
rhs.ptr_ = nullptr;
}
return *this;
}
T* release()noexcept
{
T* ret = ptr_;
ptr_ = nullptr;
return ret;
}
void reset(T* p = nullptr) noexcept
{
deleter_(ptr_);
ptr_ = p;
}
T* get() const noexcept { return ptr_; }
explicit operator bool() const noexcept { return ptr_ != nullptr; }
T& operator*() const { return *ptr_; }
T* operator->() const noexcept { return ptr_; }
private:
T* ptr_ = nullptr;
D deleter_;
};
#endif
练习 16.30:
“std::weak_ptr<std::vector<T,std::allocator<T>>>::weak_ptr”: 3 个重载中没有一个可以转换所有参数类型。
练习 16.31:
编译器将默认删除器类型设置为DebugDelete,该类型将在编译时执行。
练习 16.32:
在模板实参推断过程中,编译器使用调用函数调用中的实参类型来寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。
练习 16.33:
const转换和数组或函数到指针的转换。
练习 16.34:
template <class T> int compare(const T&, const T&);
compare("hi", "world"); // 不合法,参数类型不匹配,const char[3],const char[6].
compare("bye", "dad"); // 合法,T的类型为const char[4].
练习 16.35:
template <typename T> T calc(T, int);
template <typename T> T fcn(T, T);
double d; float f; char c;
calc(c, 'c'); // 合法, T的类型为char
calc(d, f); // 合法, T的类型为double
fcn(c, 'c'); // 合法, T的类型为char
fcn(d, f); // 不合法, d的类型为double, f的类型为float
练习 16.36:
template <typename T> f1(T, T); // 函数无返回值
template <typename T1, typename T2) f2(T1, T2); // 函数无返回值,typename T2)改为typename T2>
int i = 0, j = 42, *p1 = &i, *p2 = &j;
const int *cp1 = &i, *cp2 = &j;
f1(p1, p2); // T的类型为int*
f2(p1, p2); // T1和T2的类型都是int*
f1(cp1, cp2); // T的类型为const int*
f2(cp1, cp2); // T1和T2的类型都是const int*
f1(p1, cp1); // 不合法, p1是int*, cp1是const int*
f2(p1, cp1); // T1的类型是int*, T2的类型是const int*
练习 16.37:
可以,但必须显示指定模板类型参数。
#include<iostream>
using namespace std;
int main()
{
int i = 1; double d = 1.1;
cout << max<double>(i, d) << endl;
return 0;
}
练习 16.38:
因为当我们调用make_shared时,如果没有提供一个显示模板实参,无法推断返回类型。
练习 16.39:
#include<iostream>
#include<string>
#include<functional>
using namespace std;
template<typename T>
int compare(const T& v1, const T& v2)
{
if (less<T>()(v1, v2))
return -1;
if (less<T>()(v2, v1))
return 1;
return 0;
}
int main()
{
cout << compare<string>("him", "mom") << endl;
return 0;
}
练习 16.40:
合法,但是只有支持这个 + 0操作的类型可以被传递,并且返回类型取决于operator +返回的类型。
#include<iostream>
#include<vector>
using namespace std;
template<typename It>
auto fcn3(It beg, It end)->decltype(*beg + 0)
{
return *beg;
}
int main()
{
vector<int> vi = { 1,2,3 };
vector<string> vs = { "cpp","java"};
cout << fcn3(vi.begin(), vi.end()) << endl;
//cout << fcn3(vs.begin(), vs.end()) << endl;
return 0;
}
练习 16.41:
#include<iostream>
using namespace std;
template<typename T1, typename T2>
auto sum(T1 a, T2 b)->decltype(a + b)
{
return a + b;
}
int main()
{
int a, b;
cin >> a >> b;
cout << sum(a, b) << endl; // 无法容纳更大的数据范围
return 0;
}
练习 16.42:
当我们将一个左值int传递给函数的右值引用参数,且此右值引用指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型int &。
- X&&, X&& &,和X&& &&都折叠成类型X&
template <typename T> void g(T&& val);
int i = 0; const int ci = i;
g(i); // T: int& val: int& &&
g(ci); // T: const int& val: const int& &&
g(i * ci); // T: int val: int&&
练习 16.43:
int&
练习 16.44:
无论g的函数参数声明为T或const T&,这三种调用,T的类型都为int。
练习 16.45:
如果我们对一个像42这样的字面常量调用g, T的类型为int,我们得到一个类型vector<int>的临时变量v。如果我们对int类型的变量调用g,那么val应该是左值,T应该是int&(因为int& && == int&),那么我们将v声明为vector<int&>。但是vector的元素类型必须是可赋值的,引用是不可赋值的,因此,vector<int&>是不允许的,编译器会报错。
练习 16.46:
*elem是一个左值,std::move将其转换为一个右值引用,然后构造函数会调用移动构造函数,而不是拷贝构造函数。
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
练习 16.47:
#include<iostream>
using namespace std;
// 无法保持给定实参的左值
template <typename F, typename T1, typename T2>
void flip1(F f, T1 t1, T2 t2)
{
f(t2, t1);
}
// 保持类型信息的函数参数
// 对于接受一个左值引用的函数工作的很好,不能用于接受右值引用参数的函数
template <typename F, typename T1, typename T2>
void flip2(F f, T1&& t1, T2&& t2)
{
f(t2, t1);
}
// 使用std::forward保持类型信息
template <typename F, typename T1, typename T2>
void flip(F f, T1&& t1, T2&& t2)
{
f(std::forward<T2>(t2), std::forward<T1>(t1));
}
void f(int v1, int& v2)
{
cout << v1 << " " << ++v2 << endl;
}
void g(int&& i, int& j)
{
cout << i << " " << ++j << endl;
}
int main()
{
// 无法保持给定实参的左值
int i = 0;
f(42, i);
cout << "i = " << i << endl;
flip1(f, i, 42);
cout << "i = " << i << endl; // flip1的调用不改变i
cout << "--------------------" << endl;
int j = 0;
flip2(f, j, 42);
cout << "j = " << j << endl; // flip1的调用改变j
// 错误:不能从一个左值实例化int&&,即使传递一个右值给flip2,但函数参数是左值表达式
// flip2(g, j, 42);
cout << "--------------------" << endl;
int k = 0;
flip(g, k, 42);
cout << "k = " << k << endl;
return 0;
}
练习 16.48:
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
template<typename T> string debug_rep(const T& t);
template<typename T> string debug_rep(T* p);
string debug_rep(const string& s);
string debug_rep(char* p)
{
return debug_rep(string(p));
}
string debug_rep(const char* p)
{
return debug_rep(string(p));
}
template<typename T> string debug_rep(const T& t)
{
ostringstream ret;
ret << t;
return ret.str(); // 返回ret绑定的string的一个副本
}
template<typename T> string debug_rep( T* p)
{
ostringstream ret;
ret << "pointer: " << p; // 指针本身的值
if (p)
ret << " " << debug_rep(*p); // p指向的值
else
ret << " null pointer"; // p为空
return ret.str();
}
string debug_rep(const string& s)
{
return '"' + s + '"';
}
int main()
{
string s("hi");
cout << debug_rep(s) << endl;
cout << debug_rep("cpp") << endl;
return 0;
}
练习 16.49 && 16.50:
#include<iostream>
using namespace std;
template<typename T> void f(T)
{
cout << "f(T)" << endl;
}
template<typename T> void f(const T*)
{
cout << "f(const T*)" << endl;
}
template<typename T> void g(T)
{
cout << "g(T)" << endl;
}
template<typename T> void g(T*)
{
cout << "g(T*)" << endl;
}
int main()
{
int i = 42, *p = &i;
const int ci = 0, *p2 = &ci;
g(42); // val: int 输出:g(T) T: int 实例化: void g(int)
g(p); // val: int* 输出:g(T*) T: int 实例化: void g(int *)
g(ci); // val: const int 输出:g(T) T: const int 实例化: void g(const int)
g(p2); // val: const int* 输出:g(T*) T: const int 实例化: void g(const int *)
f(42); // val: int 输出:f(T) T: int 实例化: void f(int)
f(p); // val: int* 输出:f(T) T: int* 实例化: void f(int *)
f(ci); // val: const int 输出:f(T) T: const int 实例化: void f(const int)
f(p2); // val: const int* 输出:f(const T*) T:int 实例化: void f(const int *)
return 0;
}
练习 16.51 && 16.52:
#include<iostream>
using namespace std;
template<typename T, typename ... Args>
void foo(const T& t, const Args& ... args)
{
cout << "sizeof...(Args):" << sizeof...(Args) << endl;
cout << "sizeof...(args):" << sizeof...(args) << endl;
}
int main()
{
int i = 0; double d = 3.14; string s = "how";
foo(i, s, 42, d); // Args: string, int, double sizeof...(Args): 3 sizeof...(rest): 3
foo(s, 42, "hi"); // Args: int, const char[3] sizeof...(Args): 2 sizeof...(rest): 2
foo(d, s); // Args: string sizeof...(Args): 1 sizeof...(rest): 1
foo("hi"); // Args: None sizeof...(Args): 0 sizeof...(rest): 0
return 0;
}
练习 16.53 && 16.54:
#include<iostream>
using namespace std;
class Foo
{};
class Bar
{};
template<typename T>
ostream& print(ostream& os, const T& t)
{
return os << t;
}
template<typename T, typename... Args>
ostream& print(ostream& os, const T& t, const Args& ... args)
{
os << t << ", ";
return print(os, args...);
}
int main()
{
// 练习 16.53
print(cout, "cpp") << endl;
print(cout, "cpp", 5) << endl;
int i = 0; int* p = &i;
print(cout, "cpp", 5, 1.1, true, p) << endl;
// 练习 16.54
// 没有接受"const T"类型的<<运算符
/*Foo foo; Bar bar;
print(cout, foo, bar);*/
return 0;
}
练习 16.55:
未找到匹配的重载函数"print"
练习 16.56:
#include<iostream>
#include<sstream>
using namespace std;
string debug_rep(char* p);
string debug_rep(const char* p);
template<typename T> ostream& print(ostream& os, const T& t);
template<typename T, typename... Args> ostream& print(ostream& os, const T& t, const Args& ... args);
string debug_rep(const string& s);
template<typename T> string debug_rep(const T& t);
template<typename T> string debug_rep(T* p);
template<typename... Args>
ostream& errorMsg(ostream& os, const Args& ... args)
{
return print(os, debug_rep(args)...);
}
template<typename T>
ostream& print(ostream& os, const T& t)
{
return os << t;
}
template<typename T, typename... Args>
ostream& print(ostream& os, const T& t, const Args& ... args)
{
os << t << ", ";
return print(os, args...);
}
string debug_rep(char* p)
{
return debug_rep(string(p));
}
string debug_rep(const char* p)
{
return debug_rep(string(p));
}
template<typename T> string debug_rep(const T& t)
{
ostringstream ret;
ret << t;
return ret.str(); // 返回ret绑定的string的一个副本
}
template<typename T> string debug_rep(T* p)
{
ostringstream ret;
ret << "pointer: " << p; // 指针本身的值
if (p)
ret << " " << debug_rep(*p); // p指向的值
else
ret << " null pointer"; // p为空
return ret.str();
}
string debug_rep(const string& s)
{
return '"' + s + '"';
}
int main()
{
errorMsg(cout, 1, 1.1, true, "cpp") << endl;
return 0;
}
练习 16.57:
error_msg使用一个initializer_list来定义一个可接受可变数目实参的函数。但是所有实参必须具有相同的类型或者它们的类型可以转换为同一个公共类型。相反,可变参数函数提供了更好的灵活性。
练习 16.58:
#ifndef STRVEC_HPP
#define STRVEC_HPP
#include<string>
#include<memory>
#include<initializer_list>
#include<algorithm>
#include<utility>
using namespace std;
class StrVec
{
friend bool operator==(const StrVec&, const StrVec&);
friend bool operator!=(const StrVec&, const StrVec&);
friend bool operator<(const StrVec&, const StrVec&);
friend bool operator>(const StrVec&, const StrVec&);
friend bool operator<=(const StrVec&, const StrVec&);
friend bool operator>=(const StrVec&, const StrVec&);
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
StrVec(StrVec&&)noexcept;
StrVec& operator=(StrVec&&)noexcept;
~StrVec();
StrVec(initializer_list<string>);
StrVec& operator=(initializer_list<string>);
void push_back(const string&);
template<typename... Args>
void emplace_back(Args&&...);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
string* begin()const { return elements; }
string* end()const { return first_free; }
string& at(size_t pos) { return *(elements + pos); }
const string& at(size_t pos) const { return *(elements + pos); }
string& operator[](size_t n) { return elements[n]; }
const string& operator[](size_t n) const { return elements[n]; }
void reserve(size_t newcapacity);
void resize(size_t count);
void resize(size_t count, const string&);
private:
allocator<string> alloc;
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
void reallocate();
void alloc_n_move(size_t);
void range_initialize(const string*, const string*);
pair<string*, string*> alloc_n_copy(const string* beg, const string* end);
void free();
string* elements;
string* first_free;
string* cap;
};
pair<string*, string*> StrVec::alloc_n_copy(const string* beg, const string* end)
{
auto pbeg = alloc.allocate(end - beg);
auto pend = uninitialized_copy(beg, end, pbeg);
return pair<string*, string*>(pbeg, pend);
}
void StrVec::free()
{
if (elements)
{
for_each(elements, first_free, [this](string& s) {alloc.destroy(&s); });
alloc.deallocate(elements, cap - elements);
}
}
void StrVec::range_initialize(const string* beg, const string* end)
{
auto newdata = alloc_n_copy(beg, end);
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::StrVec(const StrVec& rhs)
{
range_initialize(rhs.begin(), rhs.end());
}
StrVec& StrVec::operator=(const StrVec& rhs)
{
auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
StrVec::StrVec(StrVec&& rhs)noexcept
:elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
StrVec& StrVec::operator=(StrVec&& rhs)noexcept
{
if (this != &rhs)
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
StrVec::~StrVec()
{
free();
}
StrVec::StrVec(initializer_list<string> il)
{
range_initialize(il.begin(), il.end());
}
StrVec& StrVec::operator=(initializer_list<string> il)
{
auto newdata = alloc_n_copy(il.begin(), il.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
void StrVec::push_back(const string& s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
}
template<typename... Args>
void StrVec::emplace_back(Args&&... args)
{
chk_n_alloc();
alloc.construct(first_free++, std::forward<Args>(args)...);
}
void StrVec::alloc_n_move(size_t newcapacity)
{
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;
for (auto beg = elements; beg != first_free; ++beg)
alloc.construct(dest++, std::move(*beg));
free();
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
void StrVec::reallocate()
{
auto newcapacity = size() ? 2 * size() : 1;
alloc_n_move(newcapacity);
}
void StrVec::reserve(size_t newcapacity)
{
if (newcapacity <= capacity())
return;
alloc_n_move(newcapacity);
}
void StrVec::resize(size_t count)
{
resize(count, string());
}
void StrVec::resize(size_t count, const string& s)
{
if (count > size())
{
if (count > capacity())
reserve(2 * count);
while (first_free != elements + count)
alloc.construct(first_free++, s);
}
else if (count < size())
{
while (first_free != elements + count)
alloc.destroy(--first_free);
}
}
bool operator==(const StrVec& lhs, const StrVec& rhs)
{
return lhs.size() == rhs.size() &&
equal(lhs.begin(), lhs.end(), rhs.begin());
}
bool operator!=(const StrVec& lhs, const StrVec& rhs)
{
return !(lhs == rhs);
}
bool operator<(const StrVec& lhs, const StrVec& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
bool operator>(const StrVec& lhs, const StrVec& rhs)
{
return rhs < lhs;
}
bool operator<=(const StrVec& lhs, const StrVec& rhs)
{
return !(rhs < lhs);
}
bool operator>=(const StrVec& lhs, const StrVec& rhs)
{
return !(lhs < rhs);
}
#endif
#ifndef VEC_H
#define VEC_H
#include<initializer_list>
#include<memory>
#include<algorithm>
using namespace std;
template<typename T> class Vec;
template<typename T> bool operator==(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator!=(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator<(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator>(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator<=(const Vec<T>&, const Vec<T>&);
template<typename T> bool operator>=(const Vec<T>&, const Vec<T>&);
template<typename T> class Vec
{
friend bool operator==<T>(const Vec<T>&, const Vec<T>&);
friend bool operator!=<T>(const Vec<T>&, const Vec<T>&);
friend bool operator< <T>(const Vec<T>&, const Vec<T>&);
friend bool operator> <T>(const Vec<T>&, const Vec<T>&);
friend bool operator<=<T>(const Vec<T>&, const Vec<T>&);
friend bool operator>=<T>(const Vec<T>&, const Vec<T>&);
public:
Vec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
Vec(initializer_list<T>);
Vec(const Vec<T>&);
Vec& operator=(const Vec<T>&);
Vec(Vec<T>&&)noexcept;
Vec& operator=(Vec<T>&&)noexcept;
~Vec();
T* begin()const { return elements; }
T* end()const { return first_free; }
void push_back(const T&);
template<typename... Args>
void emplace_back(Args&&...);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
T& at(size_t n) { return *(elements + n); }
const T& at(size_t n)const { return *(elements + n); }
T& operator[](size_t n) { return elements[n]; }
const T& operator[](size_t n)const { return elements[n]; }
void reserve(size_t new_cap);
void resize(size_t n);
void resize(size_t n, const T&);
private:
// 工具函数-拷贝控制
pair<T*, T*> alloc_n_copy(const T*, const T*);
void range_initialize(const T*, const T*);
void free();
// 工具函数-分配内存移动元素
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
void reallocate();
void alloc_n_move(size_t new_cap);
private:
T* elements;
T* first_free;
T* cap;
allocator<T> alloc;
};
// 拷贝控制工具函数
template<typename T>
pair<T*, T*> Vec<T>::alloc_n_copy(const T* beg, const T* end)
{
auto pbeg = alloc.allocate(end - beg);
auto pend = uninitialized_copy(beg, end, pbeg);
return pair<T*, T*>(pbeg, pend);
}
template<typename T>
void Vec<T>::range_initialize(const T* beg, const T* end)
{
auto data = alloc_n_copy(beg, end);
elements = data.first;
first_free = cap = data.second;
}
template<typename T>
void Vec<T>::free()
{
if (elements)
{
for_each(elements, first_free,
[this](T& obj) {alloc.destroy(&obj); });
alloc.deallocate(elements, cap - elements);
}
}
// 拷贝控制函数
template<typename T>
Vec<T>::Vec(initializer_list<T> il)
{
range_initialize(il.begin(), il.end());
}
template<typename T>
Vec<T>::Vec(const Vec<T>& rhs)
{
range_initialize(rhs.begin(), rhs.end());
}
template<typename T>
Vec<T>& Vec<T>::operator=(const Vec<T>& rhs)
{
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
template<typename T>
Vec<T>::Vec(Vec<T>&& rhs)noexcept :
elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
template<typename T>
Vec<T>& Vec<T>::operator=(Vec<T>&& rhs)noexcept
{
if (*this != rhs)
{
free();
elements = rhs.elements;
first_free = rhs.first_free;
cap = rhs.cap;
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
template<typename T>
Vec<T>::~Vec()
{
free();
}
// 工具函数-分配内存移动元素
template<typename T>
void Vec<T>::alloc_n_move(size_t new_cap)
{
auto newdata = alloc.allocate(new_cap);
auto dest = newdata;
for (auto beg = elements; beg != first_free; ++beg)
alloc.construct(dest++, std::move(*beg));
free();
elements = newdata;
first_free = dest;
cap = newdata + new_cap;
}
template<typename T>
void Vec<T>::reallocate()
{
auto new_cap = size() ? 2 * size() : 1;
alloc_n_move(new_cap);
}
// 普通成员函数
template<typename T>
void Vec<T>::push_back(const T& t)
{
chk_n_alloc();
alloc.construct(first_free++, t);
}
template<typename T>
template<typename... Args>
void Vec<T>::emplace_back(Args&&... args)
{
chk_n_alloc();
alloc.construct(first_free++, std::forward<Args>(args)...);
}
template<typename T>
void Vec<T>::reserve(size_t new_cap)
{
if (new_cap <= capacity())
return;
alloc_n_move(new_cap);
}
template<typename T>
void Vec<T>::resize(size_t n)
{
resize(n, T());
}
template<typename T>
void Vec<T>::resize(size_t n, const T& t)
{
if (n > size())
{
if (n > capacity())
reserve(2 * n);
while (first_free != elements + n)
alloc.construct(first_free++, t);
}
else if (n < size())
{
while (first_free != elements + n)
alloc.destroy(--first_free);
}
}
// 友元函数
template<typename T>
bool operator==(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lhs.size() == rhs.size()
&& equal(lhs.begin(), lhs.begin(), rhs.begin());
}
template<typename T>
bool operator!=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(lhs == rhs);
}
template<typename T>
bool operator<(const Vec<T>& lhs, const Vec<T>& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.begin(),
rhs.begin(), rhs.end());
}
template<typename T>
bool operator>(const Vec<T>& lhs, const Vec<T>& rhs)
{
return (rhs < lhs);
}
template<typename T>
bool operator<=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(rhs < lhs);
}
template<typename T>
bool operator>=(const Vec<T>& lhs, const Vec<T>& rhs)
{
return !(lhs < rhs);
}
#endif
练习 16.59:
#include"StrVec.hpp"
#include<iostream>
int main()
{
StrVec svec;
string s("cpp");
svec.emplace_back(s);
svec.emplace_back("java");
for (auto it = svec.begin(); it != svec.end(); ++it)
cout << *it << " ";
cout << endl;
return 0;
}
练习 16.60:
make_shared使用可变参数模板与std::forward(转发)机制实现将实参保持不变地传递给其他函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
练习 16.61:
#include<iostream>
#include<memory>
using namespace std;
// 使用可变参数:是因为string有多个构造函数,且参数各不相同;
// Args参数为右值引用(Args&&)和使用std::forward:是为了保持实参中类型信息的传递。
// 这样当传递一个右值string&& 对象给make_shared时,就可以使用string的移动构造函数进行初始化。
template<typename T, typename... Args>
shared_ptr<T> Make_shared(Args&&... args)
{
return shared_ptr<T>(new T(std::forward<Args>(args)...));
}
int main()
{
auto p1 = Make_shared<int>(42);
cout << *p1 << endl;
auto p2 = Make_shared<string>(10, 'c');
cout << *p2 << endl;
return 0;
}
练习 16.62:
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include<iostream>
#include<string>
using namespace std;
template<class T> class std::hash;
class Sales_data
{
friend class std::hash<Sales_data>;
friend istream& operator>>(istream&, Sales_data&);
friend ostream& operator<<(ostream&, Sales_data&);
friend bool operator==(const Sales_data&, const Sales_data&);
friend Sales_data operator+(const Sales_data&, const Sales_data&);
public:
Sales_data() = default;
Sales_data(const string& s) : bookNo(s) {}
Sales_data(const string& s, unsigned n, double p)
: bookNo(s), units_sold(n), revenue(n* p) {}
Sales_data(istream& is);
Sales_data& operator=(const string&);
Sales_data& operator+=(const Sales_data&);
explicit operator string()const { return isbn(); }
explicit operator double()const { return avg_price(); }
string isbn()const { return bookNo; }
private:
double avg_price() const { return units_sold ? revenue / units_sold : 0; }
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
istream& operator>>(istream&, Sales_data&);
ostream& operator<<(ostream&, Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);
namespace std
{
template<>
struct hash<Sales_data>
{
typedef size_t result_type;
typedef Sales_data argument_type;
size_t operator()(const Sales_data& s)const
{
return hash<string>()(s.bookNo) ^
hash<unsigned>()(s.units_sold) ^
hash<double>()(s.revenue);
}
};
}
#endif
#include"Sales_data.h"
Sales_data::Sales_data(istream& is)
{
is >> *this;
}
Sales_data& Sales_data::operator=(const string& isbn)
{
*this = Sales_data(isbn);
return *this;
}
Sales_data& Sales_data::operator+=(const Sales_data& rhs)
{
if (this->isbn() == rhs.isbn())
{
this->units_sold += rhs.units_sold;
this->revenue += rhs.revenue;
return *this;
}
}
istream& operator>>(istream& is, Sales_data& data)
{
double price = 0.0;
is >> data.bookNo >> data.units_sold >> price;
if (is)
data.revenue = data.units_sold * price;
else
data = Sales_data();
return is;
}
ostream& operator<<(ostream& os, Sales_data& data)
{
os << data.bookNo << " " << data.units_sold << " " << data.revenue << " "
<< data.avg_price();
return os;
}
bool operator==(const Sales_data& lhs, const Sales_data& rhs)
{
return lhs.isbn() == rhs.isbn() &&
lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue;
}
Sales_data operator+(const Sales_data& lhs, const Sales_data& rhs)
{
if (lhs.isbn() == rhs.isbn())
{
Sales_data sum = lhs;
sum += rhs;
return sum;
}
}
#include <iostream>
#include <memory>
#include <unordered_set>
#include "Sales_data.h"
int main()
{
unordered_multiset<Sales_data> mset;
Sales_data sd("Bible", 10, 0.98);
mset.emplace(sd);
mset.emplace("C++ Primer", 5, 9.99);
for (const auto& item : mset)
cout << "the hash code of " << item.isbn()
<< ":\n0x" << hex << hash<Sales_data>()(item)
<< endl;
return 0;
}
练习 16.63 && 64:
#include<iostream>
#include<vector>
using namespace std;
template<typename T>
size_t count(const vector<T>& vec, T val)
{
size_t n = 0;
for (auto& elem : vec)
if (elem == val)
++n;
return n;
}
template<>
size_t count(const vector<const char*>& vec, const char* val)
{
size_t n = 0;
for (auto& elem : vec)
if (elem == val)
++n;
return n;
}
int main()
{
vector<double> dvec = { 3.3,2.2,1.1,4.4,2.2,5.5,2.2 };
cout << count(dvec, 2.2) << endl;
vector<int> ivec = { 1,2,4,5,6 };
cout << count(ivec, 3) << endl;
vector<string> svec = { "cpp","java","python","cpp","golang" };
cout << count(svec, string("cpp")) << endl;
vector<const char*> cvec = { "cpp","java","python","cpp","golang" };
cout << count(cvec, "cpp") << endl;
return 0;
}
练习 16.65:
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
template<typename T> string debug_rep(const T& t);
template<typename T> string debug_rep(T* p);
template<>
string debug_rep(char* p)
{
return string(p);
}
template<>
string debug_rep(const char* p)
{
return string(p);
}
template<typename T> string debug_rep(const T& t)
{
ostringstream ret;
ret << t;
return ret.str();
}
template<typename T> string debug_rep(T* p)
{
ostringstream ret;
ret << "pointer: " << p;
if (p)
ret << " " << debug_rep(*p);
else
ret << " null pointer";
return ret.str();
}
int main()
{
cout << debug_rep("cpp") << endl;
char p[] = "java";
cout << debug_rep(p) << "\n";
return 0;
}
练习 16.66:
重载改变函数匹配。特例化不会影响函数匹配。
练习 16.67:
特例化版本本质是原始模板的一个实例,不是函数重载。因此它不会影响函数匹配。