练习16.1
当编译器实例化一个模版时,它使用实际的模版实参来代替对应的模版参数来创建出模版的一个新“实例”,这些编译器生成的版本通常被称为模板的实例
练习16.2
template<typename T> bool compare(T&lhs,T&rhs){ return lhs < rhs; } int main(int argc, char* argv[]) { int i = 10, j = 11; string s1 = "01", s2 = "000"; cout << compare(i, j) << endl; cout << compare(s1, s2) << endl; }
练习16.3
error C2678: 二进制“<”: 没有找到接受“const T”类型的左操作数的运算符(或没有可接受的转换)
with
[
T=Sales_data
]
练习16.4
template<typename T1,typename T2> T1 findVal(T1 beg, T1 end, T2 val) {for (T1 it = beg; it != end; ++it) { if (*it == val)return it; } return end; } int main(int argc, char* argv[]) { vector<int> v{ 1,2,3,4,5,6 }; list<int> l{ 1,2,3,4,5,6 }; auto it1 = findVal(v.begin(), v.end(), 4); cout << *it1 << endl; auto it2 = findVal(l.begin(), l.end(), 4); cout << *it2 << endl; }
练习16.5
template<typename T,unsigned N> void print(const T(&arr)[N]) { for (auto& elem : arr) { cout << elem << " "; } } int main(int argc, char* argv[]) { int j[2] = { 0,1 }; int k[10] = { 0,1,2,3,4,5,6,7,8,9 }; string s[] = { "dog", "cat", "rat" }; print(j); print(k); print(s); }
练习16.6
template <class _Ty, size_t _Size> _NODISCARD constexpr _Ty* begin(_Ty (&_Array)[_Size]) noexcept { return _Array; } template <class _Ty, size_t _Size> _NODISCARD constexpr _Ty* end(_Ty (&_Array)[_Size]) noexcept { return _Array + _Size; }
练习16.7
template<typename T,size_t N> size_t arr_size(const T(&arr)[N]) { return N; }
练习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); void insert(ListItem<elemType>* ptr, elemType value); private: //ListItem* front, * end; ListItem<elemType>* front, * end; }; int main(int argc, char* argv[]) { List<int> l(); }
练习16.12
#ifndef _BLOB_H #define _BLOB_H #define LIST_INIT #include <vector> #include <string> #include <memory> #include <stdexcept> #ifdef LIST_INIT #include <initializer_list> #endif // forward declaration needed for friend declaration in Blob template<typename> class BlobPtr; template<typename> class ConstBlobPtr; template<typename T> class Blob { friend class BlobPtr<T>; friend class ConstBlobPtr<T>; friend bool operator==(const Blob<T>& lhs, const Blob<T>& rhs); friend bool operator!=(const Blob<T>& lhs, const Blob<T>& rhs); public: typedef std::vector<std::string>::size_type size_type; // constructors Blob() : data(std::make_shared<std::vector<std::string>>()) { } #ifdef LIST_INIT Blob(std::initializer_list<std::string> il); #else Blob(std::string*, std::string*); #endif Blob(const Blob<T>& sb) { data = std::make_shared<std::vector<std::string>>(*sb.data); } Blob& operator=(const Blob<T>& sb) { data = std::make_shared<std::vector<std::string>>(*sb.data); } std::string& operator[](size_t n); const std::string& operator[](size_t n)const; // size operations size_type size() const { return data->size(); } bool empty() const { return data->empty(); } // add and remove elements void push_back(const std::string& t) { data->push_back(t); } void push_back(std::string&& t) { data->push_back(std::move(t)); } void pop_back(); // element access const std::string& front(); const std::string& back(); // interface to BlobPtr BlobPtr<T> begin(); // can't be defined until BlobPtr is BlobPtr<T> end(); ConstBlobPtr<T> cbegin(); // can't be defined until BlobPtr is ConstBlobPtr<T> cend(); long count() { return data.use_count(); // and wptr.use_count(); } private: std::shared_ptr<std::vector<std::string>> data; // throws msg if data[i] isn't valid void check(size_type i, const std::string& msg) const; }; // constructor #ifdef LIST_INIT template<typename T> inline Blob<T>::Blob<T>(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)) { } #else template<typename T> inline Blob<T>::Blob<T>(std::string* b, std::string* e) : data(std::make_shared<std::vector<std::string>>(b, e)) { } #endif template<typename T> inline std::string& Blob<T>::operator[](size_t n) { check(n, "out of range"); return data->at(n); } template<typename T> inline const std::string& Blob<T>::operator[](size_t n) const { check(n, "out of range"); return data->at(n); } // BlobPtr throws an exception on attempts to access a nonexistent template<typename T> class BlobPtr { friend bool operator==(const BlobPtr<T>&, const BlobPtr<T>&); public: BlobPtr() : curr(0) { } BlobPtr(Blob<T>& a, size_t sz = 0) : wptr(a.data), curr(sz) { } std::string& deref() const; BlobPtr& incr(); // prefix version BlobPtr& decr(); // prefix version // added a public member function to Blob and BlobPrts long count() { return wptr.use_count(); // and wptr.use_count(); } std::string& operator[](size_t n); const std::string& operator[](size_t n)const; BlobPtr& operator++(); BlobPtr<T> operator++(int); BlobPtr& operator--(); BlobPtr<T> operator--(int); BlobPtr& operator+=(size_t n); BlobPtr<T> operator+(size_t n)const; BlobPtr& operator-=(size_t n); BlobPtr<T> operator-(size_t n)const; std::string& operator*()const; std::string* operator->()const; private: // check returns a shared_ptr to the vector if the check succeeds std::shared_ptr<std::vector<std::string>> check(std::size_t, const std::string&) const; // store a weak_ptr, which means the underlying vector might be destroyed std::weak_ptr<std::vector<std::string>> wptr; std::size_t curr; // current position within the array }; // BlobPtr throws an exception on attempts to access a nonexistent element template<typename T> class ConstBlobPtr { friend bool operator==(const ConstBlobPtr&, const ConstBlobPtr&); public: ConstBlobPtr() : curr(0) { } ConstBlobPtr(const Blob<T>& a, size_t sz = 0) : wptr(a.data), curr(sz) { } std::string& deref() const; ConstBlobPtr& incr(); // prefix version ConstBlobPtr& decr(); // prefix version // added a public member function to Blob and BlobPrts long count() { return wptr.use_count(); // and wptr.use_count(); } const std::string& operator*()const; const std::string* operator->()const; private: // check returns a shared_ptr to the vector if the check succeeds std::shared_ptr<std::vector<std::string>> check(std::size_t, const std::string&) const; // store a weak_ptr, which means the underlying vector might be destroyed std::weak_ptr<std::vector<std::string>> wptr; std::size_t curr; // current position within the array }; template<typename T> inline std::string& BlobPtr<T>::deref() const { auto p = check(curr, "dereference past end"); return (*p)[curr]; // (*p) is the vector to which this object points } template<typename T> inline std::string& BlobPtr<T>::operator[](size_t n) { auto ret = check(n, "out of range"); return (*ret)[n]; } template<typename T> inline const std::string& BlobPtr<T>::operator[](size_t n) const { auto ret = check(n, "out of range"); return (*ret)[n]; } template<typename T> inline BlobPtr<T>& BlobPtr<T>::operator++() { check(curr, "increment past out end of BlobPtr"); ++curr; 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--() { --curr; check(curr, "increment past begin end of BlobPtr"); 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+=(size_t n) { curr += n; check(curr, "increment past out end 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) { curr -= n; check(curr, "increment past begin end 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 std::string& BlobPtr<T>::operator*() const { auto p = check(curr, "dereference past end"); return (*p)[curr]; } template<typename T> inline std::string* BlobPtr<T>::operator->() const { return &this->operator*(); } template<typename T> inline std::shared_ptr<std::vector<std::string>> BlobPtr<T>::check(std::size_t i, const std::string& msg) const { auto ret = wptr.lock(); // is the vector still around? if (!ret) throw std::runtime_error("unbound BlobPtr"); if (i >= ret->size()) throw std::out_of_range(msg); return ret; // otherwise, return a shared_ptr to the vector } // prefix: return a reference to the incremented object template<typename T> inline BlobPtr<T>& BlobPtr<T>::incr() { // if curr already points past the end of the container, can't increment it check(curr, "increment past end of BlobPtr"); ++curr; // advance the current state return *this; } template<typename T> inline BlobPtr<T>& BlobPtr<T>::decr() { // if curr is zero, decrementing it will yield an invalid subscript --curr; // move the current state back one element} check(-1, "decrement past begin of BlobPtr"); return *this; } template<typename T> inline void Blob<T>::pop_back() { check(0, "pop_back on empty Blob"); data->pop_back(); } template<typename T> inline const std::string& Blob<T>::front() { check(0, "front on empty Blob"); return data->front(); } template<typename T> inline const std::string& Blob<T>::back() { check(0, "back on empty Blob"); return data->back(); } // begin and end members for Blob template<typename T> inline BlobPtr<T> Blob<T>::begin() { return BlobPtr<T>(*this); } template<typename T> inline BlobPtr<T> Blob<T>::end() { auto ret = BlobPtr<T>(*this, data->size()); return ret; } // begin and end members for Blob template<typename T> inline ConstBlobPtr<T> Blob<T>::cbegin() { return ConstBlobPtr<T>(*this); } template<typename T> inline ConstBlobPtr<T> Blob<T>::cend() { auto ret = ConstBlobPtr<T>(*this, data->size()); return ret; } template<typename T> inline bool operator==(const Blob<T>& lhs, const Blob<T>& rhs) { return *lhs.data == *rhs.data; } template<typename T> inline bool operator!=(const Blob<T>& lhs, const Blob<T>& rhs) { return !(lhs == rhs); } // named equality operators for BlobPtr template<typename T> inline bool operator==(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs) { auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); // if the underlying vector is the same if (l == r) // then they're equal if they're both null or // if they point to the same element return (!r || lhs.curr == rhs.curr); else return false; // if they point to difference vectors, they're not equal } template<typename T> inline bool operator!=(const BlobPtr<T>& lhs, const BlobPtr<T>& rhs) { return !(lhs == rhs); } // named equality operators for BlobPtr template<typename T> inline bool operator==(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs) { auto l = lhs.wptr.lock(), r = rhs.wptr.lock(); // if the underlying vector is the same if (l == r) // then they're equal if they're both null or // if they point to the same element return (!r || lhs.curr == rhs.curr); else return false; // if they point to difference vectors, they're not equal } template<typename T> inline bool operator!=(const ConstBlobPtr<T>& lhs, const ConstBlobPtr<T>& rhs) { return !(lhs == rhs); } template<typename T> inline const std::string& ConstBlobPtr<T>::operator*() const { auto p = check(curr, "dereference past end"); return (*p)[curr]; } template<typename T> inline const std::string* ConstBlobPtr<T>::operator->() const { return &this->operator*(); } #endif
练习16.13
operator==<T>(const BlobPtr<T>&, const BlobPtr<T>&);
练习16.14
screen.h
#ifndef SCREEN_H_ #define SCREEN_H_ #include<string> //#include "Window_mgr.h" using pos = std::string::size_type; template<pos X, pos Y> class Screen { public: friend class Window_mgr; Screen<X,Y>() = default; //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,' '){} Screen<X, Y>(char c=' ') :height(X), width(Y), contents(height* width, c) {} Screen<X, Y> set(char); Screen<X, Y> set(pos, pos,char); Screen<X, Y> move(pos, pos); Screen<X, Y> display(std::ostream& os); const Screen<X, Y> display(std::ostream& os)const; pos size() const; private: pos cursor = 0; pos height = 0, width = 0; std::string contents; void do_display(std::ostream& os)const { os << contents; } }; template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::set(char c) { contents[cursor] = c; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::set(pos row, pos col,char c) { cursor = row * width + col; contents[row * width + col] = c; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::move(pos row, pos col) { char newc = contents[cursor]; contents[cursor] = contents[row * width + col]; contents[row * width + col] = newc; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::display(std::ostream& os) { do_display(os); return *this; } template<pos X, pos Y> inline const Screen<X, Y> Screen<X, Y>::display(std::ostream& os) const { do_display(os); return *this; } template<pos X, pos Y> inline pos Screen<X, Y>::size() const { return height * width; } #endif // !SCREEN_H_
Window_mgr.h
#ifndef WINDOW_MGR_H_ #define WINDOW_MGR_H_ #include <vector> #include "Screen.h" template<pos,pos> class Screen; template<pos X, pos Y> class Window_mgr { public: using ScreenIndex=std::vector<Screen<X,Y>>::size_type ; void clear(ScreenIndex); Window_mgr() = default; Window_mgr(Screen& s) { screens.push_back(s); } private: std::vector<Screen> screens; }; template<pos X, pos Y> inline void Window_mgr<X, Y>::clear(ScreenIndex i) { if (screens.empty())return; Screen<X, Y>& s = screens[i]; s.contents = std::string(s.height * s.width, ' '); } #endif // !WINDOW_MGR_H_
练习16.15
#ifndef SCREEN_H_ #define SCREEN_H_ #include<string> //#include "Window_mgr.h" using pos = std::string::size_type; template<pos X, pos Y> class Screen { public: friend class Window_mgr; friend std::istream& operator>>(std::istream& is, Screen<X, Y>& s){ char a; is >> a; std::string temp(X* Y, a); s.contents = temp; return is; } friend std::ostream& operator<<(std::ostream& os, Screen<X, Y>& s){ unsigned int i, j; for (i = 0; i < s.height; i++) { os << s.contents.substr(0, X) << std::endl; } return os; } //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,' '){} Screen<X, Y>(char c=' ') :height(X), width(Y), contents(height* width, c) {} Screen<X, Y> set(char); Screen<X, Y> set(pos, pos,char); Screen<X, Y> move(pos, pos); Screen<X, Y> display(std::ostream& os); const Screen<X, Y> display(std::ostream& os)const; pos size() const; private: pos cursor = 0; pos height = 0, width = 0; std::string contents; void do_display(std::ostream& os)const { os << contents; } }; template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::set(char c) { contents[cursor] = c; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::set(pos row, pos col,char c) { cursor = row * width + col; contents[row * width + col] = c; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::move(pos row, pos col) { char newc = contents[cursor]; contents[cursor] = contents[row * width + col]; contents[row * width + col] = newc; return *this; } template<pos X, pos Y> inline Screen<X, Y> Screen<X, Y>::display(std::ostream& os) { do_display(os); return *this; } template<pos X, pos Y> inline const Screen<X, Y> Screen<X, Y>::display(std::ostream& os) const { do_display(os); return *this; } template<pos X, pos Y> inline pos Screen<X, Y>::size() const { return height * width; } #endif // !SCREEN_H_
int main(int argc, char* argv[]) { Screen<10,15> dtest; cin >> dtest; cout << dtest << std::endl; }
练习16.16
#ifndef _VEC_H_ #define _VEC_H_ #include<memory> #include <algorithm> template<typename T> class Vec { friend bool operator==(const Vec<T>&, const Vec<T>&); friend bool operator!=(const Vec<T>&, const Vec<T>&); public: Vec() :elements(nullptr), first_free(nullptr), cap(nullptr) {} Vec(const Vec<T>&); Vec(std::initializer_list <T> il); Vec<T>& operator=(const Vec<T>&); Vec<T>& operator=(std::initializer_list<T> il); Vec(Vec<T>&& sv)noexcept; Vec<T>& operator=(Vec<T>&&); ~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); size_t capacity(); void resize(size_t n); void resize(size_t n, T t); const T& at(size_t pos) const { return *(elements + pos); } T& operator[](size_t n); const T& operator[](size_t n)const; private: static std::allocator<T> alloc; void chk_n_alloc() { if (size() == capacity())reallocate(); } std::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> Vec<T>::Vec(const Vec<T>& sv) { auto newdata = alloc_n_copy(sv.begin(), sv.end()); elements = sv.elements; first_free = cap = newdata.second; } template<typename T> inline Vec<T>::Vec(std::initializer_list<T> il) { auto newdata = alloc_n_copy(il.begin(), il.end()); elements = newdata.first; first_free = cap = newdata.second; } template<typename T> inline Vec<T>& Vec<T>::operator=(const Vec<T>& sv) { auto data = alloc_n_copy(sv.begin(), sv.end()); free(); elements = data.first; first_free = cap = data.second; return *this; } template<typename T> inline Vec<T>& Vec<T>::operator=(std::initializer_list<T> il) { auto newdata = alloc_n_copy(il.begin(), il.end()); free(); elements = newdata.first; first_free = cap = newdata.second; return *this; } template<typename T> inline Vec<T>::Vec(Vec<T>&& sv) noexcept :elements(sv.elements), first_free(sv.first_free), cap(sv.cap) { sv.elements = sv.first_free = sv.cap = nullptr; } template<typename T> inline Vec<T>& Vec<T>::operator=(Vec<T>&& rhs) { 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> inline void Vec<T>::push_back(const T& s) { chk_n_alloc(); alloc.construct(first_free++, s); } template<typename T> inline void Vec<T>::reserve(size_t n) { if (n > capacity()) { auto newdata = alloc.allocate(n); auto dest = newdata; auto elem = elements; for (size_t i = 0; i != size(); ++i) alloc.construct(dest++, std::move(*elements)); free(); elements = newdata; first_free = dest; cap = elements + n; } } template<typename T> inline size_t Vec<T>::capacity() { return cap - elements;; } template<typename T> inline void Vec<T>::resize(size_t n) { resize(n, T()); } template<typename T> inline void Vec<T>::resize(size_t n, T t) { if (n > size()) { if (n > capacity()) reserve(n * 2); for (size_t i = size(); i != n; ++i) alloc.construct(first_free++, t); } else if (n < size()) { while (first_free != elements + n) alloc.destroy(--first_free); } } template<typename T> inline T& Vec<T>::operator[](size_t n) { if (size() > n && n >= 0)return *(elements + n); } template<typename T> inline const T& Vec<T>::operator[](size_t n) const { if (size() > n && n >= 0)return *(elements + n); } template<typename T> inline std::pair<T*, T*> Vec<T>::alloc_n_copy(const T* b, const T* e) { auto data = alloc.allocate(e - b); return { data,std::uninitialized_copy(b,e,data) }; } template<typename T> inline void Vec<T>::free() { if (elements) { std::for_each(elements, first_free, [this](T& p) {alloc.destroy(&p); }); alloc.deallocate(elements, cap - elements); } } template<typename T> inline void Vec<T>::reallocate() { auto newcapacity = size() ? 2 * size() : 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> bool operator==(const Vec<T>& lhs, const Vec<T>& rhs) { if (lhs.size() != rhs.size()) { return false; } else { for (auto l_iter = lhs.begin(), r_iter = rhs.begin(); l_iter != lhs.end(); ++l_iter, ++r_iter) { if (*l_iter != *r_iter) { return false; } } } return true; } template<typename T> inline bool operator!=(const Vec<T>& lhs, const Vec<T>& rhs) { return !(lhs == rhs); } #endif // !_VEC_H_
练习16.17
声明为typename的类型参数和声明为class的类型参数没有什么不同,但在模板类型参数的类型成员时必须通过关键字typename显式的告诉编译器该名字是一个类型
练习16.18
(a) template <typename T, U, typename V> void f1(T, U, V);=>template<typename T, typename U, typename V>void f1(T, U, V);
(b) template <typename T> T f2(int &T);=>template<typename T>T f2(int& );
(c) inline template <typename T> T foo(T, unsigned int*);=>template <typename T> inline T foo(T, unsigned int*);
(d) template <typename T> f4(T, T);合法
(e) typedef char Ctype;
template <typename Ctype> Ctype f5(Ctype a);=>template <typename Ctype> Ctype f5(Ctype a);
练习16.19
template<typename T> void print_c(const T& _container) { using size_type = typename T::size_type; for (auto i = 0; i != _container.size(); ++i) cout << _container[i] << " "; } int main(int argc, char* argv[]) { vector<int> v{ 0,1,2,3,4,5 }; print_c(v); }
练习16.20
template<typename T> void print_c(const T& _container) { for (auto i = begin(_container); i != end(_container); ++i) cout << *i << " "; } int main(int argc, char* argv[]) { vector<int> v{ 0,1,2,3,4,5 }; print_c(v); }
练习16.21
#include <ostream> #include <iostream> #ifndef _DEBUGDELETE_H_ #define _DEBUGDELETE_H_ class DebugDelete { public: DebugDelete(std::ostream &s=std::cerr):os(s){} template<typename T>void operator()(T* p)const { os << "deleting unique_ptr" << std::end; delete p; } private: std::ostream& os; }; #endif // !_DEBUGDELETE_H_
练习16.22
#include <fstream> using std::ifstream; using std::ofstream; #include <iostream> using std::cin; using std::cout; using std::endl; #include <map> using std::map; using std::multimap; #include <set> using std::multiset; using std::set; #include <sstream> using std::istringstream; #include <string> using std::string; #include <unordered_map> using std::unordered_map; #include <vector> #include "StrVec.h" #include <algorithm> using std::vector; #ifndef TEXTQUERT_H_ #define TEXTQUERT_H_ #include "DebugDelete.h" class QueryResult; class TextQuery { friend class QueryResult; public: TextQuery() :text(new StrVec, DebugDelete()), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete()) {} TextQuery(ifstream& ifs); QueryResult query(string s) const; ~TextQuery(); private: std::shared_ptr <StrVec> text; std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words; }; class QueryResult { public: friend std::ostream& print(std::ostream& os, const QueryResult qr); using QueryIterator = set<size_t>::iterator; public: QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrVec> i) :word(w), nos(new set<size_t>, DebugDelete()), inputs(new StrVec, DebugDelete()) { nos = n; inputs = i; } ~QueryResult(); QueryIterator begin() { return nos->begin(); } QueryIterator end() { return nos->end(); } std::shared_ptr <StrVec> get_file() { return inputs; } private: string word; std::shared_ptr<set<size_t>> nos; std::shared_ptr<StrVec> inputs; }; QueryResult::~QueryResult() { } inline TextQuery::TextQuery(ifstream& ifs) : text(new StrVec, DebugDelete()), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete()) { size_t size=0; if (ifs) { for (string line; getline(ifs, line,'.'); ++size) { text->push_back(line); istringstream iss(line); size = text->size(); for (string text, word; iss >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); // use reference avoid count of shared_ptr add. auto& nos = (*query_words)[word]; if (!nos) nos.reset(new std::set<size_t>); nos->insert(size); } } } } inline QueryResult TextQuery::query(string s) const{ static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>, DebugDelete()); auto found = query_words->find(s); if (found == query_words->end()) { cout << s + " is not in the text" << endl; return QueryResult(s, nodate, text); } else return QueryResult(s, found->second, text); } TextQuery::~TextQuery() { } std::ostream& print(std::ostream& os, const QueryResult qr) { os << qr.word << " occurs " << qr.nos->size() << " times" << endl; for (auto i : *qr.nos) { os << " (line " << i + 1 << ") " << qr.inputs->at(i) << std::endl; } return os; } #endif // !TEXTQUERT_H_
练习16.23
#include <fstream> using std::ifstream; using std::ofstream; #include <iostream> using std::cin; using std::cout; using std::endl; #include <map> using std::map; using std::multimap; #include <set> using std::multiset; using std::set; #include <sstream> using std::istringstream; #include <string> using std::string; #include <unordered_map> using std::unordered_map; #include <vector> #include "StrVec.h" #include <algorithm> using std::vector; #ifndef TEXTQUERT_H_ #define TEXTQUERT_H_ #include "DebugDelete.h" class QueryResult; class TextQuery { friend class QueryResult; public: TextQuery() :text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>")) {} TextQuery(ifstream& ifs); QueryResult query(string s) const; ~TextQuery(); private: std::shared_ptr <StrVec> text; std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words; }; class QueryResult { public: friend std::ostream& print(std::ostream& os, const QueryResult qr); using QueryIterator = set<size_t>::iterator; public: QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrVec> i) :word(w), nos(new set<size_t>, DebugDelete("QueryResult::set<size_t>")), inputs(new StrVec, DebugDelete("QueryResult::StrVec")) { nos = n; inputs = i; } ~QueryResult(); QueryIterator begin() { return nos->begin(); } QueryIterator end() { return nos->end(); } std::shared_ptr <StrVec> get_file() { return inputs; } private: string word; std::shared_ptr<set<size_t>> nos; std::shared_ptr<StrVec> inputs; }; QueryResult::~QueryResult() { } inline TextQuery::TextQuery(ifstream& ifs) : text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>")) { size_t size=0; if (ifs) { for (string line; getline(ifs, line,'.'); ++size) { text->push_back(line); istringstream iss(line); size = text->size(); for (string text, word; iss >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); // use reference avoid count of shared_ptr add. auto& nos = (*query_words)[word]; if (!nos) nos.reset(new std::set<size_t>); nos->insert(size); } } } } inline QueryResult TextQuery::query(string s) const{ static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>,DebugDelete("TextQuery::std::set<size_t>")); auto found = query_words->find(s); if (found == query_words->end()) { cout << s + " is not in the text" << endl; return QueryResult(s, nodate, text); } else return QueryResult(s, found->second, text); } TextQuery::~TextQuery() { } std::ostream& print(std::ostream& os, const QueryResult qr) { os << qr.word << " occurs " << qr.nos->size() << " times" << endl; for (auto i : *qr.nos) { os << " (line " << i + 1 << ") " << qr.inputs->at(i) << std::endl; } return os; } #endif // !TEXTQUERT_H_
int main(int argc, char* argv[]) { ifstream ifs(argv[1]); TextQuery tq(ifs); print(cout, tq.query("abc")); }
输出结果
abc is not in the text deleting unique_ptr:QueryResult::set<size_t> deleting unique_ptr:QueryResult::StrVec abc occurs 0 times deleting unique_ptr:TextQuery::map<string, std::shared_ptr<set<size_t>>> deleting unique_ptr:TextQuery::StrVec deleting unique_ptr:TextQuery::std::set<size_t>
练习16.24
template<typename T> template<typename It> inline Blob<T>::Blob(It& b, It& e) { data(std::make_shared<std::vector<std::string>>(b, e)); }
练习16.25
extern template class vector<string>;//不会在本文件中生成实例化代码 template class vector<Sales_data>;//实例化该代码
练习16.26
不可以,因为NoDefault没有提供模版的定义
练习16.27
template <typename T> class Stack { }; void f1(Stack<char>); //(a)这是对 f1 的声明,f1 的参数是 Stack<char>,需要在这里检查实参和形参的类型是否匹配(然后调用拷贝构造函数), //编译时就需要 Stack<char> 的定义,所以需要实例化,注意,这里就算是引用传参而不是值传参,也一样是需要实例化的, //因为需要检查引用的类型与绑定的对象的类型是否一致; class Exercise { Stack<double>& rds; //(b)引用需要在初始化时绑定到一个相同类型的对象上,在调用这句话时,一定是想把它绑定到一个对象上, //例如在构造函数中为 rsd 赋初值(必须赋初值,不然会报错)。由于在编译阶段需要检查引用类型和绑定的对象的类型是否一致, //因此需要知道 Stack<double> 的定义,所以需要实例化; Stack<int> si; //(c)编译时需要知道创建 si 成员需要多大空间,需要Stack<int> 的定义,因此需要实例化; }; int main() { Stack<char>* sc; //(d)指针与引用不同,它不是一定要初始化,这里 sc 没有初始化,它就是一个未定义的地址。它不需要 Stack<char> 的定义, //所以不需要实例化。如果初始化了,那么才需要检查指针类型与初始化的对象类型是否一致,这样才需要 Stack<char> 的定义, //才需要对 Stack 实例化。 f1(*sc); //(e)不需要实例化 int iObj = sizeof(Stack<string>); //(f)需要实例化,因为需要知道 Stack<string> 的定义,才能知道 sizeof(Stack<string>)。 }
练习16.28
#ifndef _SHARED_PTR_H_ #define _SHARED_PTR_H_ #include <iostream> using std::string; template<typename T> class Shared_ptr { friend void swap(Shared_ptr&, Shared_ptr&); public: Shared_ptr(const std::string& s = std::string()) :ps(new std::string(s)), use(new size_t(1)) {} Shared_ptr(const Shared_ptr& hp) :ps(hp.ps), use(hp.use) { ++* use; } Shared_ptr& operator=(Shared_ptr hp) { swap(*this, hp); return *this; } Shared_ptr& operator=(Shared_ptr&& hp)noexcept { if (this != &hp) { delete ps; ps = hp.ps; hp.ps = nullptr; } return *this; } string& getPs() { return *ps; } ~Shared_ptr() { if (-- * use == 0) { delete ps; delete use; } } private: T* ps; size_t* use; }; template<typename T> void swap(Shared_ptr<T>& lhp, Shared_ptr<T>& rhp) { using std::swap; swap(lhp.ps, rhp.ps); swap(lhp.use, rhp.use); } #endif // !_SHARED_PTR_H_
#ifndef _UNIQUE_PTR_H_ #define _UNIQUE_PTR_H_ #include <iostream> using std::string; template<typename T> class Unique_ptr { friend void swap(Unique_ptr&, Unique_ptr&); public: Unique_ptr(const std::string& s = std::string()) :ps(new std::string(s)){} Unique_ptr(const Unique_ptr& hp) :ps(hp.ps) { } Unique_ptr& operator=(Unique_ptr hp) { swap(*this, hp); return *this; } Unique_ptr& operator=(Unique_ptr&& hp)noexcept { if (this != &hp) { delete ps; ps = hp.ps; hp.ps = nullptr; } return *this; } string& getPs() { return *ps; } ~Unique_ptr() { delete ps; } private: T* ps; }; template<typename T> void swap(Unique_ptr<T>& lhp, Unique_ptr<T>& rhp) { using std::swap; swap(lhp.ps, rhp.ps); } #endif // !_UNIQUE_PTR_H_
练习16.29
练习16.30
练习16.31
由于删除器为类内的简单函数,所以可以被处理为编译器的内联形式
练习16.32
编译器使用函数调用中的实参类型来寻找模版实参,用这些模版实参生成的函数版本与给定的函数调用作为匹配
练习16.33
const转换:将非const对象的引用(或指针)传递给一个const的引用(或指针)形参
数组或函数指针转换:如果函数形参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换
练习16.34
(a)合法,T的类型是string
(b)合法,T的类型是string
练习16.35
(a)合法,T的类型是char
(b)合法,T的类型是double
(c)合法,T的类型是char
(d)不合法,传入实参d和f类型不同,从第一个参数推断出的模版实参为double,从第二个参数推断出的模版实参为float,类型不匹配
练习16.36
(a) f1(int*,int*)
(b)f2(int*,int*)
(c) f1(const int*,const int*)
(d)f2(const int*,const int*)
(e) 报错,因为const int*是底层const,无法忽略,因此int*和int*类型不同
(f)f2(int*,const int*)
练习16.37
可以,但是返回结果可能需要进行类型转换,如max<double> (int,double);如果返回的是int型则需转为double型
练习16.38
make_shared需要模版实参来判断该模版需要创建多大的内存空间
练习16.39
compare<std::string>("hello", "world")
练习16.40
合法,对可以传递的实参类型需要支持+运算符,返回类型是返回序列元素的引用
练习16.41
template<typename T1,typename T2> auto sum(T1& lval, T2& rval)->typename std::remove_reference<decltype(lval+rval)>::type { return lval + rval; }
练习16.42
template<typename T>void g(T&& val); int i = 0; const int ci = i; g(i);//int& g(ci);//const int& g(i * ci);//int&&
练习16.43
ci将值赋给i然后传入i,传入的是左值,模板参数为int&
练习16.44
template<typename T>void g(T val); int i = 0; const int ci = i; g(i);//int g(ci);//const int g(i * ci);//int
template<typename T>void g(const T& val); int i = 0; const int ci = i; g(i);//int g(ci);//int g(i * ci);//int
练习16.45
当使用字面常量,T将为int。 当使用int变量,T将为int&。编译的时候将会报错,因为没有办法对这种类型进行内存分配,无法创建vector<int&>
练习16.46
*对elem解引用获得值,是左值类型,再使用move转为右值引用并赋给dest
练习16.47
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 sum(int i, int j) { cout << i << " " << j << endl; } void sum1(int& i, int& j) { cout << i << " " << j << endl; } void sum2(int&& i, int&& j) { cout << i << " " << j << endl; } int main(void) { int i = 0, j = 10; flip(sum,i, j); flip(sum1, i, j); flip(sum2, 0, 10); }
练习16.48
template<typename T>string debug_rep(const T& t) { std::ostringstream ret; ret << t; return ret.str(); } template<typename T>string debug_rep(T* p) { std::ostringstream ret; ret <<"pointer: " <<p; if (p) ret << debug_rep(*p); else ret << " null pointer"; return ret.str(); } string debug_rep(char* p) { return debug_rep(string(p)); } string debug_rep(const char* p) { return debug_rep(string(p)); }
练习16.49
g(42); //g(T ) g(p); //g(T*) g(ci); //g(T) g(p2); //g(T*) f(42); //f(T) f(p); //f(T) f(ci); //f(T) f(p2); //f(const T*)
练习16.50
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(void) { int i = 42, * p = &i; const int ci = 0, * p2 = &ci; g(42); g(p); g(ci); g(p2); f(42); f(p); f(ci); f(p2); }
练习16.51
foo(i, s, 42, d);// sizeof...(Args): 3,sizeof...(rest) : 3 foo(s, 42, "hi");// sizeof...(Args) : 2,sizeof...(rest) : 2 foo(d, s);// sizeof...(Args) : 1,sizeof...(rest) : 1 foo("hi");// sizeof...(Args) : 0,sizeof...(rest) : 0
练习16.52
template <typename T, typename ... Args> void foo(const T& t, const Args& ... rest) { cout << "sizeof...(Args): " << sizeof...(Args) << endl; cout << "sizeof...(rest): " << sizeof...(rest) << endl; }; int main(void) { int i = 0; double d = 3.14; string s = "how now brown cow"; foo(i, s, 42, d); foo(s, 42, "hi"); foo(d, s); foo("hi"); }
练习16.53
template <typename T> std::ostream& print(std::ostream& os, const T& t) { return os << t<<endl; } template <typename T,typename ... Args> std::ostream& print(std::ostream & os, const T& t,const Args& ... rest) { return print(os<<t<<" ",rest...); } int main(void) { string s = "hello"; print(cout, 1); print(cout, 1,s,"world"); print(cout, 1, s, "world",10.5,1e5); }
练习16.54
无法编译
练习16.55
无限递归执行本函数
练习16.56
template<typename T>string debug_rep(const T& t) { std::ostringstream ret; ret << t; return ret.str(); } template<typename T>string debug_rep(T* p) { std::ostringstream ret; ret << "pointer: " << p; if (p) ret << debug_rep(*p); else ret << " null pointer"; return ret.str(); } string debug_rep(char* p) { return debug_rep(string(p)); } string debug_rep(const char* p) { return debug_rep(string(p)); } template<typename...Args> std::ostream& errorMsg(std::ostream& os, const Args& ... rest) { return print(os , debug_rep(rest)...); } int main(void) { string s = "hello"; errorMsg(cout, s, "primer", 4, 8.6, '5'); }
练习16.57
可变参数版本的errorMsg不要求实参参数类型相同,但需要递归调用,效率低
使用参数初始化列表initializer list也可以定义一个可接受可变参数数目的函数,但是所有的实参都必须具有相同的类型(或者可转变为相同的类型)
练习16.58
template<typename ...Arg> inline void StrVec::emplace_back(Arg && ...args) { chk_n_alloc(); alloc.construct(first_free++, std::forward<Arg>(args)...); }
template<typename T> template<typename ...Arg> inline void Vec<T>::emplace_back(Arg && ...args) { chk_n_alloc(); alloc.construct(first_free++, std::forward<Arg>(args)...); }
练习16.59
会在 construst
函数中转发扩展包。
练习16.60
make_shared
是一个可变模版函数,它将参数包转发然后用其构造一个对象,再然后返回一个指向该对象的智能指针。
练习16.61
#ifndef _SHARED_PTR_H_ #define _SHARED_PTR_H_ #include <iostream> using std::string; template<typename T> class Shared_ptr { friend void swap(Shared_ptr&, Shared_ptr&); public: Shared_ptr(const std::string& s = std::string()) :ps(new std::string(s)), use(new size_t(1)) {} Shared_ptr(const Shared_ptr& hp) :ps(hp.ps), use(hp.use) { ++* use; } template<typename It> Shared_ptr& operator=(Shared_ptr hp) { swap(*this, hp); return *this; } Shared_ptr& operator=(Shared_ptr&& hp)noexcept { if (this != &hp) { delete ps; ps = hp.ps; hp.ps = nullptr; } return *this; } string& getPs() { return *ps; } ~Shared_ptr() { if (-- * use == 0) { delete ps; delete use; } } template <typename T, class... Args> Shared_ptr<T> make_shared(Args&&... args) { return Shared_ptr<T>(new T(std::forward<Args>(args)...)); } private: T* ps; size_t* use; }; template<typename T> void swap(Shared_ptr<T>& lhp, Shared_ptr<T>& rhp) { using std::swap; swap(lhp.ps, rhp.ps); swap(lhp.use, rhp.use); } #endif // !_SHARED_PTR_H_
#ifndef _SHARED_PTR_H_ #define _SHARED_PTR_H_ #include <iostream> using std::string; template<typename T> class Shared_ptr { friend void swap(Shared_ptr&, Shared_ptr&); public: Shared_ptr(const std::string& s = std::string()) :ps(new std::string(s)), use(new size_t(1)) {} Shared_ptr(const Shared_ptr& hp) :ps(hp.ps), use(hp.use) { ++* use; } template<typename It> Shared_ptr& operator=(Shared_ptr hp) { swap(*this, hp); return *this; } Shared_ptr& operator=(Shared_ptr&& hp)noexcept { if (this != &hp) { delete ps; ps = hp.ps; hp.ps = nullptr; } return *this; } string& getPs() { return *ps; } ~Shared_ptr() { if (-- * use == 0) { delete ps; delete use; } } template <typename T, class... Args> Shared_ptr<T> make_shared(Args&&... args) { return Shared_ptr<T>(new T(std::forward<Args>(args)...)); } private: T* ps; size_t* use; }; template<typename T> void swap(Shared_ptr<T>& lhp, Shared_ptr<T>& rhp) { using std::swap; swap(lhp.ps, rhp.ps); swap(lhp.use, rhp.use); } #endif // !_SHARED_PTR_H_
练习16.62
在Sales_data添加友元函数operator==的重载 friend bool operator==(const Sales_data& lhs, const Sales_data& rhs); inline bool operator==(const Sales_data& lhs, const Sales_data& rhs) { return lhs.units_sold == rhs.units_sold && lhs.revenue == rhs.revenue && lhs.isbn() == rhs.isbn(); } 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; }; size_t hash<Sales_data>::operator()(const Sales_data& s) const { return hash<string>()(s.bookNo)^ hash<unsigned>()(s.units_sold)^ hash<double>()(s.revenue); } }
int main(void) { Sales_data sales_data1("001-01", 1, 100); Sales_data sales_data2; Sales_data sales_data3("001-02"); Sales_data sales_data4(std::cin); std::unordered_multiset<Sales_data> SDset; SDset.emplace(sales_data1); SDset.emplace("001-03", 1, 200); SDset.emplace(sales_data3); SDset.emplace(sales_data4); for (const auto& item : SDset) std::cout << "the hash code of " << item.isbn() << ": 0x" << std::hex << std::hash<Sales_data>()(item) << " "; return 0; }
练习16.63
练习16.64
template<typename T> size_t count(vector<T>const&vec, T val) { size_t cnt = 0; for (const auto& it : vec) { if (val == it)++cnt; } return cnt; } template<> size_t count(vector<const char*>const&vec, const char* val) { size_t cnt = 0; for (auto const& it : vec) { if (0==strcmp(val,it))++cnt; } return cnt; } size_t count(vector<string>const& vec, const char* val) { string str(val); return count(vec,str); } int main(void) { std::vector<double> vd = { 1, 2, 3, 3.14, 4, 3.14, 5, 6.28 }; std::vector<int> vi = { 1, 2, 3, 3, 4, 3, 5, 6 }; std::vector<std::string> vs = { "a", "bb", "ccc", "dddd" }; std::vector<const char*> vcp = { "a", "bb", "ccc", "dddd" }; std::cout << count( vd, 3.14) << std::endl; std::cout << count( vi, 3) << std::endl; std::cout << count( vs, "a") << std::endl; std::cout << count( vcp, "a") << std::endl; return 0; }
练习16.65
template<typename T>string debug_rep(const T& t) { std::ostringstream ret; ret << t; return ret.str(); } template<typename T>string debug_rep(T* p) { std::ostringstream ret; ret << "pointer: " << p; if (p) ret << debug_rep(*p); else ret << " null pointer"; return ret.str(); } template<> string debug_rep(char* p) { return debug_rep(string(p)); } template<> string debug_rep(const char* p) { return debug_rep(string(p)); }
练习16.66
重载函数会改变函数匹配。
练习16.67
不会影响,特例化的本质是实例化一个模版,而非重载它。因此,特例化不影响函数匹配