cppPrimer学习16th

cppPrimer学习16th

TODO#

Copy
16.22 16.23

16.1#

Copy
给出实例化的定义 我们在调用模块的时候,传递确定的参数,编译器为我们构造真实的函数或者对象

16.2#

Copy
// 16.2 编写你自己的compare版本 #include <iostream> template <typename T> int compare(const T &a, const T &b) { if (a > b) return 1; if (a < b) return -1; return 0; } int main(int argc, char const *argv[]) { std::cout << compare(1, 2) << std::endl; while (1) ; return 0; }

16.3#

Copy
提示未定义 operator< error: no match for 'operator>' (operand types are 'const Sales_data' and 'const Sales_data') // 16.2 编写你自己的compare版本 #include <iostream> class Sales_data { private: int a; public: Sales_data() : a(0) {} ~Sales_data() {} }; template <typename T> int compare(const T &a, const T &b) { if (a > b) return 1; if (a < b) return -1; return 0; } int main(int argc, char const *argv[]) { Sales_data a; Sales_data b; std::cout << compare(1, 2) << std::endl; std::cout << compare(a, b) << std::endl; while (1) ; return 0; }

16.4#

Copy
// 16.4 编写行为类似标准库find算法的模版.函数需要两个模版类型参数,一个表示函数的迭代器参数,另一个表示值的类型. // 使你的函数在一个vector<int> 和 list<string>中查找给定值 #include <vector> #include <list> #include <string> #include <iostream> template <typename it_type, typename value_type> it_type find(const it_type begin, const it_type end, const value_type val) { for (auto it = begin; it != end; it++) { if (*it == val) return it; } return end; } template <typename it_type, typename value_type> std::ostream &PrintFind(const it_type &begin, const it_type &end, const value_type &val, std::ostream &o = std::cout) { it_type find_it = find(begin, end, val); if (find_it == end) return o << "Null to find"; else return o << *find_it; } int main(int argc, char const *argv[]) { std::vector<int> vs({1, 2, 3, 4, 5, 6, 7, 8, 9}); std::cout << *find(vs.begin(), vs.end(), 2) << std::endl; PrintFind(vs.begin(), vs.end(), 2) << std::endl; PrintFind(vs.begin(), vs.end(), 10) << std::endl; std::list<std::string> ls({"123", "456", "ABC"}); PrintFind(ls.begin(), ls.end(), "999") << std::endl; while (1) ; return 0; }

16.5#

Copy
// 16.5 编写一个printf 支持任意大小任意元素类型的数组 #include <iostream> #include <string> template <typename elem_type, int size> void print(elem_type (&arr)[size]) { for (auto ch : arr) { std::cout << ch << std::endl; } } int main(int argc, char const *argv[]) { std::string as[] = {"123", "456", "789"}; int ai[] = {1, 2, 3, 4, 5, 6}; print(as); print(ai); while (1) ; return 0; }

16.6#

Copy
//16.6 你认为一个接受数组实参的标准库函数 begin 和end是如何工作的,定义你自己版本的begin和end // 也就是定义 begin(array)和end(array) #include <iostream> #include <string> template <typename elem_type, size_t size> elem_type *Begin(elem_type (&array)[size]) { return array; } template <typename elem_type, size_t size> elem_type *End(elem_type (&array)[size]) { return array + size; } int main(int argc, char const *argv[]) { std::string as[] = {"123", "456", "789"}; for (auto i = Begin(as); i != End(as); i++) std::cout << *i << std::endl; while (1) ; return 0; }

16.7#

Copy
//16.7 编写一个 constexpr 模版,返回给定参数的大小 template <typename T, unsigned N> constexpr unsigned SizeOfArray(const T (&arr)[N]) { return N; }

16.8#

Copy
//16.8 在97页非关键概念中,c++程序在for喜欢用!= 替换 < 的原因是什么 迭代器一般定义了 != 和= 但是不一定定义了<

16.9#

Copy
// 16.9 什么是函数模版? 什么是类模版? 函数有参数是模版,编译器自动推断模版参数 类模版,有参数是模版,需要手动定义模版参数的

16.10#

Copy
//16.10 当一个类模版被实例化,会发生什么? 1. 生成类的非模版函数 2. 生成需要使用的类的模版函数

16.11#

Copy
// 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); private: ListItem *front, *end; }; // 修改注释部分 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; };

16.12#

Copy
// 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员 #include <vector> #include <memory> #include <string> #include <iostream> #include <initializer_list> #include <exception> #include <algorithm> template <typename T> class BlobPtr; template <typename T> class Blob; template <typename T> class ConstBlobPtr; template <typename T> bool operator==(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator!=(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator<(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator>(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator<=(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator>=(const Blob<T> &a, const Blob<T> &b); template <typename T> class Blob { friend BlobPtr<T>; friend ConstBlobPtr<T>; friend bool operator==<T>(const Blob<T> &a, const Blob<T> &b); friend bool operator!=<T>(const Blob<T> &a, const Blob<T> &b); // clang-format off friend bool operator< <T>(const Blob<T> &a, const Blob<T> &b); friend bool operator> <T>(const Blob<T> &a, const Blob<T> &b); // clang-format on friend bool operator<=<T>(const Blob<T> &a, const Blob<T> &b); friend bool operator>=<T>(const Blob<T> &a, const Blob<T> &b); // 以下两个应该是为了外部方便获取类型 typedef T value_type; typedef typename std::vector<T>::size_type size_type; private: std::shared_ptr<std::vector<T>> data; void check(size_type i, const std::string &msg) const; public: Blob() : data(std::make_shared<std::vector<T>>()) {} Blob(const Blob<T> &s) : data(std::make_shared<std::vector<T>>(*s.data)) {} Blob(Blob<T> &&a) noexcept : data(std::move(a.data)) {} Blob &operator=(const Blob<T> &s); Blob &operator=(Blob<T> &&) noexcept; Blob(std::initializer_list<T> il) : data(std::make_shared<std::vector<T>>(il)) {} size_type size() const { return data->size(); } bool empty() const { return data->empty(); } void push_back(T &val) { data->push_back(val); }; void push_back(const T &val) { data->push_back(std::move(val)); } void pop_back(); T &back(); const T &back() const; T &front(); const T &front() 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; void print(std::ostream &o); }; template <typename T> Blob<T> &Blob<T>::operator=(const Blob<T> &s) { data = std::make_shared<std::vector<T>>(*s.data); return *this; } template <typename T> Blob<T> &Blob<T>::operator=(Blob<T> &&s) noexcept { if (this != s) { data = std::move(s.data); s.data = nullptr; } return *this; } template <typename T> void Blob<T>::print(std::ostream &o) { for (auto ch : (*data)) o << ch << ","; o << std::endl; } template <typename T> void Blob<T>::check(size_type i, const std::string &msg) const { if (i >= size()) { throw std::out_of_range(msg); } } template <typename T> void Blob<T>::pop_back() { check(0, "empty to pop_back"); data->pop_back(); } template <typename T> T &Blob<T>::back() { check(0, "Get empty Back()"); return data->back(); } template <typename T> const T &Blob<T>::back() const { check(0, "Get empty Back()"); return data->back(); } template <typename T> T &Blob<T>::front() { check(0, "Get empty front()"); return data->front(); } template <typename T> const T &Blob<T>::front() const { check(0, "Get empty front()"); return data->front(); } template <typename T> T &Blob<T>::operator[](size_type i) { check(i, "Get [" + std::to_string(i) + "]"); return data->at(i); } template <typename T> const T &Blob<T>::operator[](size_type i) const { check(i, "Get [" + std::to_string(i) + "]"); return data->at(i); } template <typename T> BlobPtr<T> Blob<T>::begin() { return BlobPtr<T>(*this); } template <typename T> BlobPtr<T> Blob<T>::end() { return BlobPtr<T>(*this, size()); } template <typename T> ConstBlobPtr<T> Blob<T>::cbegin() const { return ConstBlobPtr<T>(*this); } template <typename T> ConstBlobPtr<T> Blob<T>::cend() const { return ConstBlobPtr<T>(*this, size()); } //**************************************************************************** template <typename T> bool operator==(const Blob<T> &a, const Blob<T> &b) { return (*a.data == *b.data); } template <typename T> bool operator!=(const Blob<T> &a, const Blob<T> &b) { return !(a == b); } template <typename T> bool operator<(const Blob<T> &a, const Blob<T> &b) { return std::lexicographical_compare(a.data->begin(), a.data->end(), b.data->begin(), b.data->end()); } template <typename T> bool operator>(const Blob<T> &a, const Blob<T> &b) { return (b < a); } template <typename T> bool operator<=(const Blob<T> &a, const Blob<T> &b) { return !(b > a); } template <typename T> bool operator>=(const Blob<T> &a, const Blob<T> &b) { return !(a < b); } //**************************************************************************** // 定义 Blob::iterator 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 { private: std::weak_ptr<std::vector<T>> wptr; std::size_t curr; std::shared_ptr<std::vector<T>> check(size_t i, const std::string &msg) const; public: friend bool operator==<T>(const BlobPtr<T> &a, const BlobPtr<T> &b); friend bool operator!=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b); // clang-format off friend bool operator< <T>(const BlobPtr<T> &a, const BlobPtr<T> &b); friend bool operator> <T>(const BlobPtr<T> &a, const BlobPtr<T> &b); friend bool operator<=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b); friend bool operator>=<T>(const BlobPtr<T> &a, const BlobPtr<T> &b); // clang-format on BlobPtr() : curr(0) {} BlobPtr(const Blob<T> &pt, size_t at = 0) : wptr(pt.data), curr(at) {} T &operator*() { return check(curr, "Get elem[] out of range")->at(curr); } T &operator[](size_t at) { return check(at, "Get elem[] out of range")->at(at); } const T &operator*() const { return check(curr, "Get elem[] out of range")->at(curr); } const T &operator[](size_t at) const { return check(at, "Get elem[] out of range")->at(at); } const T *operator->() const { return &this->operator*(); } T *operator->() { return &this->operator*(); } BlobPtr operator++(); BlobPtr operator++(int); BlobPtr operator--(); BlobPtr operator--(int); BlobPtr &operator+=(size_t); BlobPtr &operator-=(size_t); BlobPtr operator+(size_t) const; BlobPtr operator-(size_t) const; }; template <typename T> std::shared_ptr<std::vector<T>> BlobPtr<T>::check(size_t i, const std::string &msg) const { auto spt = wptr.lock(); if (spt) { // 使用之前必须复制到 shared_ptr if (i >= spt->size()) throw std::out_of_range(msg); } else { throw std::runtime_error("unbound Blob<T>Ptr"); } return spt; } // 前置++,先++,再返回 template <typename T> BlobPtr<T> BlobPtr<T>::operator++() { check(curr, "++"); curr++; return *this; } template <typename T> BlobPtr<T> BlobPtr<T>::operator++(int) { auto ret = *this; ++*this; return *this; } // 前置++,先++,再返回 template <typename T> BlobPtr<T> BlobPtr<T>::operator--() { check(curr, "--"); curr--; return *this; } template <typename T> BlobPtr<T> BlobPtr<T>::operator--(int) { auto ret = *this; --*this; return *this; } template <typename T> BlobPtr<T> &BlobPtr<T>::operator+=(size_t off) { curr += off; check(curr, "increment past end of Blob<T>Ptr"); return *this; } template <typename T> BlobPtr<T> &BlobPtr<T>::operator-=(size_t off) { curr -= off; check(curr, "increment past end of Blob<T>Ptr"); return *this; } template <typename T> BlobPtr<T> BlobPtr<T>::operator+(size_t off) const { BlobPtr<T> ret = *this; ret += off; return ret; } template <typename T> BlobPtr<T> BlobPtr<T>::operator-(size_t off) const { BlobPtr<T> ret = *this; ret -= off; return ret; } //*********** friend *******************************// template <typename T> bool operator==(const BlobPtr<T> &a, const BlobPtr<T> &b) { return (a.curr == b.curr); } template <typename T> bool operator!=(const BlobPtr<T> &a, const BlobPtr<T> &b) { return !(a == b); } template <typename T> bool operator<(const BlobPtr<T> &a, const BlobPtr<T> &b) { return (a.curr < b.curr); } template <typename T> bool operator>(const BlobPtr<T> &a, const BlobPtr<T> &b) { return (b < a); } template <typename T> bool operator<=(const BlobPtr<T> &a, const BlobPtr<T> &b) { return !(a > b); } template <typename T> bool operator>=(const BlobPtr<T> &a, const BlobPtr<T> &b) { return !(a < b); } // template <typename T> // std::ostream &operator<<(std::ostream &o, const T &Blob_val) // { // } //**************************************************************************** // 定义 Blob::iterator 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 { private: std::weak_ptr<std::vector<T>> wptr; std::size_t curr; std::shared_ptr<std::vector<T>> check(size_t i, const std::string &msg) const; public: friend bool operator==<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); friend bool operator!=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); // clang-format off friend bool operator< <T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); friend bool operator> <T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); friend bool operator<=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); friend bool operator>=<T>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b); // clang-format on ConstBlobPtr() : curr(0) {} ConstBlobPtr(const Blob<T> &pt, size_t at = 0) : wptr(pt.data), curr(at) {} const T &operator*() const { return check(curr, "Get elem[] out of range")->at(curr); } const T &operator[](size_t at) const { return check(at, "Get elem[] out of range")->at(at); } const T *operator->() const { return &this->operator*(); } ConstBlobPtr operator++(); ConstBlobPtr operator++(int); ConstBlobPtr operator--(); ConstBlobPtr operator--(int); ConstBlobPtr &operator+=(size_t); ConstBlobPtr &operator-=(size_t); ConstBlobPtr operator+(size_t) const; ConstBlobPtr operator-(size_t) const; }; template <typename T> std::shared_ptr<std::vector<T>> ConstBlobPtr<T>::check(size_t i, const std::string &msg) const { auto spt = wptr.lock(); if (spt) { // 使用之前必须复制到 shared_ptr if (i >= spt->size()) throw std::out_of_range(msg); } else { throw std::runtime_error("unbound Blob<T>Ptr"); } return spt; } // 前置++,先++,再返回 template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator++() { check(curr, "++"); curr++; return *this; } template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator++(int) { auto ret = *this; ++*this; return *this; } // 前置++,先++,再返回 template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator--() { check(curr, "--"); curr--; return *this; } template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator--(int) { auto ret = *this; --*this; return *this; } template <typename T> ConstBlobPtr<T> &ConstBlobPtr<T>::operator+=(size_t off) { curr += off; check(curr, "increment past end of Blob<T>Ptr"); return *this; } template <typename T> ConstBlobPtr<T> &ConstBlobPtr<T>::operator-=(size_t off) { curr -= off; check(curr, "increment past end of Blob<T>Ptr"); return *this; } template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator+(size_t off) const { ConstBlobPtr<T> ret = *this; ret += off; return ret; } template <typename T> ConstBlobPtr<T> ConstBlobPtr<T>::operator-(size_t off) const { ConstBlobPtr<T> ret = *this; ret -= off; return ret; } //*********** friend *******************************// template <typename T> bool operator==(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return (a.curr == b.curr); } template <typename T> bool operator!=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return !(a == b); } template <typename T> bool operator<(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return (a.curr < b.curr); } template <typename T> bool operator>(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return (b < a); } template <typename T> bool operator<=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return !(a > b); } template <typename T> bool operator>=(const ConstBlobPtr<T> &a, const ConstBlobPtr<T> &b) { return !(a < b); } int main(int argc, char const *argv[]) { try { std::string hello = "hello"; Blob<std::string> blob_s({"1"}); blob_s.pop_back(); // 触发check 异常 //blob_s.pop_back(); blob_s.push_back("2"); blob_s.push_back(hello); // std::cout << blob_s.size() << std::endl; blob_s.print(std::cout); std::cout << blob_s.back() << std::endl; std::cout << blob_s[blob_s.size() - 1] << std::endl; // 测试 iterator BlobPtr<std::string> blob_pt1(blob_s); std::cout << blob_pt1[1] << std::endl; // 测试迭代器 std::cout << "By iterator" << std::endl; for (auto b = blob_s.begin(); b != blob_s.end(); b++) { std::cout << *b << std::endl; } } catch (const std::exception &msg) { std::cout << msg.what() << std::endl; } { Blob<std::string> sb1{"a", "b", "c"}; Blob<std::string> sb2 = sb1; sb2[2] = "b"; if (sb1 > sb2) { for (auto iter = sb2.cbegin(); iter != sb2.cend(); ++iter) std::cout << *iter << " "; std::cout << std::endl; } ConstBlobPtr<std::string> iter(sb2); std::cout << iter->size() << std::endl; } while (1) ; return 0; }

16.13#

Copy
// 16.3 解释你为BlobPtr的相等和关系运算符选择那种类型的友好关系 模版参数T 一直的 重载都为其友元关系

16.14#

16.15#

Copy
// 16.14 编写Screen类模版,用非类型参数定义Screen的高和宽,可以当宏使用 #include <string> #include <algorithm> #include <iostream> //using pos = int; using pos = std::string::size_type; template <pos, pos> class Screen; template <pos H, pos W> std::istream &operator>>(std::istream &, Screen<H, W> &); template <pos H, pos W> std::ostream &operator<<(std::ostream &, const Screen<H, W> &); template <pos H, pos W> class Screen { friend std::istream &operator>><H, W>(std::istream &, Screen<H, W> &); friend std::ostream &operator<<<H, W>(std::ostream &, const Screen<H, W> &); private: pos curr = 0; std::string contents; public: Screen() = default; Screen(char c) : contents(H * W, c) {} char get() const { return contents[curr]; } char get(pos a, pos b) const { return contents[a * W + b]; } Screen &set(char c) { contents[curr++] = c; curr = std::min(curr, H * W); return *this; } Screen &set(pos a, pos b, char c) { contents[a * W + b] = c; return *this; } Screen &move(pos a, pos b); }; template <pos H, pos W> Screen<H, W> &Screen<H, W>::move(pos a, pos b) { curr = a * W + b; return *this; } template <pos H, pos W> std::istream &operator>>(std::istream &is, Screen<H, W> &s) { std::string input; is >> input; for (char ch : input) s.set(ch); return is; } template <pos H, pos W> std::ostream &operator<<(std::ostream &os, const Screen<H, W> &s) { for (pos r = 0; r != H; ++r) { for (pos c = 0; c != W; ++c) { os << s.get(r, c); } os << std::endl; } return os; } int main() { Screen<5, 5> screen('x'); screen.set(2, 2, 'o'); std::cout << screen << std::endl; std::cout << "please input some characters as you like:"; std::cin >> screen; std::cout << screen << std::endl; while (1) ; { /* code */ } } // xxxxx // xxxxx // xxoxx // xxxxx // xxxxx // please input some characters as you like:1234512345123451234512345999 // 12345 // 12345 // 12345 // 12345 // 12345

16.17#

Copy
在定义模板参数类型的时候,typenameclass 没什么不同 在 有些时候需要使用 模板类的类型的时候,需要加上typename,因为默认识别为类的成员 p593 T::x a; T是模板,有两种理解 1. x是静态成员,与a相*------默认是这个 2. 定义一个a变量,类型是T::x

16.18#

Copy
// 解释下面的代码是否合法 > (a) template <typename T, U, typename V> void f1(T, U, V); > (b) template <typename T> T f2(int &T); > (c) inline template <typename T> T foo(T, unsigned int*); > (d) template <typename T> f4(T, T); > (e) typedef char Ctype; > template <typename Ctype> Ctype f5(Ctype a); a. template <typename T, typename U, typename V> void f1(T, U, V); b. template <typename T> T f2(int &a); // typename 被隐藏 c. template <typename T> inline T foo(T, unsigned int*); //inline的位置 d. template <typename T> void f4(T, T); // 提供返回类型 e. 隐藏了typedef

16.19#

16.20#

Copy
// 16.19 接受容器的引用,打印容器的元素.使用 size_type 和size 控制打印 // 16.20 使用迭代器 #include <iostream> #include <vector> #include <list> #include <string> using namespace std; template <typename T> printv(const T &v) { for (typename T::size_type i = 0; i < v.size(); i++) cout << v.at(i) << "<>"; cout << endl; } template <typename T> printv2(const T &v) { for (auto c = v.begin(); c != v.end(); c++) cout << *c << "<>"; cout << endl; } int main(int argc, char const *argv[]) { vector<int> v1({1, 2, 3, 4, 5, 6, 7}); printv(v1); //因为printv使用的是 size 不是迭代器,所以不能用list list<string> v2({"123", "456"}); printv2(v2); while (1) ; return 0; }

16.21#

Copy
// 16.21 实现自己的DebugDelete版本 #include <iostream> #include <memory> using namespace std; class DebugDelete { private: std::ostream &dbgos; public: DebugDelete(std::ostream &o = std::cout) : dbgos(o) {} template <typename T> void operator()(T *elem) const { dbgos << "delete by DebugDelete" << std::endl; delete elem; } }; int main(int argc, const char **argv) { DebugDelete d; int *a = new int; d(a); int *b = new int; DebugDelete()(b); { std::unique_ptr<int, DebugDelete> ui(new int, DebugDelete()); // ui.release(); 释放ui但保留内存 // ui.reset(); 释放ui内存的东西,会调用DebugDelete std::cout << "/* message */" << std::endl; } while (1) ; return 0; }

16.24#

Copy
// 16.24 为你的Blob添加一个构造函数支持两个迭代器 // 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员 // 16.24 template <typename type_it> Blob(type_it a, type_it b) : data(std::make_shared<std::vector<T>>(a, b)) {} try { std::list<std::string> ls({"A1", "A2", "A3"}); Blob<std::string> blob_s(ls.begin(), ls.end()); blob_s.print(std::cout); } catch (const std::exception &e) { std::cerr << e.what() << '\n'; }

16.25#

Copy
// 16.25 解释下面的语句 // 显式实例化,需要在其他的地方定义 extern template class vector<string>; // 定义 template class vector<Sales_data>;

16.26#

Copy
// 16.26 假设Nodefault 是一个没有默认构造函数的类,我们可以显式实例化 vecctor<NoDefault> 吗? 不能,因为vector需要调用默认的构造函数

16.27#

Copy
// 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) } /* a. 没有,只是一个声明语句,当调用的时候实例化 b. 没有,这里只是创建一个指针,不需要实例化 c 有,这是一个非模板的类,创造对象 d 没有,指针和引用不需要 e 有 Stack<char> f 编译阶段实例化,但是只是临时的应该 */ // 测试方法 // Solution from [How is a template instantiated? - Stack Overflow](https://stackoverflow.com/questions/21598635/how-is-a-template-instantiated) #include <iostream> using namespace std; template <typename T> class Stack { typedef typename T::ThisDoesntExist StaticAssert; // T::NotExisting doesn't exist at all! }; void f1(Stack<char>); // No instantiation, compiles class Exercise { Stack<double> &rsd; // No instantiation, compiles (references don't need instantiation, are similar to pointers in this) Stack<int> si; // Instantiation! Doesn't compile!! }; int main(){ Stack<char> *sc; // No Instantiation, this compiles successfully since a pointer doesn't need instantiation f1(*sc); // Instantiation of Stack<char>! Doesn't compile!! int iObj = sizeof(Stack< std::string >); // Instantiation of Stack<std::string>, doesn't compile!! }

16.28#

Copy
// 16.28 编写自己的shared_ptr 和 unique_ptr // shared_ptr 保存一个指针,参数为value type* 按照delete是返回void的函数 using DelFuncPtr = void (*)(T*); // unique_ptr 保存的是删除器的类,因为不会被改变 #include <vector> #include <string> #include <iostream> //********************************************************************************************************* /* 0. 参考声明 template< class T > class shared_ptr; 1. 内容指针,引用计数指针,删除器的函数指针 2. 构造函数参考,先实现默认构造,即带一个指针和一个删除器 3. 拷贝构造 4. 拷贝赋值,这里需要释放原来的空间,可以使用 swap 传递值的方式 来实现 5. 所以我们先实现swap void swap( shared_ptr& r ) noexcept; 6. 析构函数,判断引用,判断是否nullptr 7. void reset( Y* ptr, Deleter d ); */ template <class T> class SharedPtr { using DelFuncPtr = void (*)(T *); private: T *ptr_ = nullptr; size_t *count_ptr_ = nullptr; DelFuncPtr del_ = nullptr; public: SharedPtr(T *ptr = nullptr, DelFuncPtr del = nullptr) : ptr_(ptr), del_(del), count_ptr_(new size_t(ptr_ != nullptr)) {} SharedPtr(const SharedPtr &s) : ptr_(s.ptr_), del_(s.del_), count_ptr_(s.count_ptr_) { ++*s.count_ptr_; } SharedPtr &operator=(SharedPtr s) //这里使用值传递,会先复制一份 { //交换自己和临时的,临时的在退出的时候会自动调用析构释放 swap(s); return *this; } void reset(T *ptr = nullptr, DelFuncPtr d = nullptr) { auto news = SharedPtr(ptr, d); swap(news); } void swap(SharedPtr &r) noexcept { using std::swap; swap(ptr_, r.ptr_); swap(count_ptr_, r.count_ptr_); swap(del_, r.del_); } ~SharedPtr() { if (ptr_ == nullptr) return; if (0 == --*count_ptr_) { del_ == nullptr ? delete (ptr_) : del_(ptr_); delete count_ptr_; } ptr_ = nullptr; count_ptr_ = nullptr; } T *get() const noexcept { return ptr_; } size_t use_count() const noexcept { return *count_ptr_; } T &operator*() const noexcept { return *ptr_; } T *operator->() const noexcept { return ptr_; } //检查 *this 是否存储非空指针,即是否有 get() != nullptr explicit operator bool() const noexcept { return get() != nullptr; } }; //********************************************************************************************************* /**unique_ptr 保存的是删除器的类,因为不会被改变 */ class Delete { public: template <typename T> void operator()(T *ptr) const { delete ptr; } }; template <typename T, typename D = Delete> class UniquePtr { private: T *ptr_ = nullptr; D del_; public: UniquePtr(T *ptr = nullptr, const D &d = D()) : ptr_(ptr), del_(d) {} ~UniquePtr() { del_(ptr_); } UniquePtr(const UniquePtr &) = delete; UniquePtr &operator=(const UniquePtr &) = delete; UniquePtr(UniquePtr &&other) noexcept : ptr_(other.ptr_), del_(std::move(other.del_)) { other.ptr_ = nullptr; } UniquePtr &operator=(UniquePtr &&other) noexcept { if (this != &other) { reset(); ptr_ = other.ptr_; del_ = std::move(other.del_); other.ptr_ = nullptr; } return *this; } UniquePtr &operator=(std::nullptr_t) noexcept { reset(); return *this; } T *release() noexcept { T *ret = ptr_; ptr_ = nullptr; return ret; } void reset(T *ptr = nullptr) { del_(ptr_); ptr_ = ptr; } void swap(UniquePtr &other) noexcept { using std::swap; swap(ptr_, other.ptr_); swap(del_, other.del_); } T *get() const noexcept { return ptr_; } D &get_deleter() noexcept { return del_; } const D &get_deleter() const noexcept { return del_; } T &operator*() const noexcept { return *ptr_; } T *operator->() const noexcept { return ptr_; } T &operator[](size_t i) const { return ptr_[i]; } //检查 *this 是否存储非空指针,即是否有 get() != nullptr explicit operator bool() const noexcept { return get() != nullptr; } }; //********************************************************************************************************* class DebugDelete { private: std::ostream &dbgos; public: DebugDelete(std::ostream &o = std::cout) : dbgos(o) {} template <typename T> void operator()(T *elem) const { dbgos << "delete by DebugDelete" << std::endl; delete elem; } }; int main(int argc, const char **argv) { { using std::string; using std::vector; DebugDelete d; string *mystring = new string("123456"); //SharedPtr<string> myshared_string(mystring, [](string *p) {std::cout << "Call delete from lambda...\n";delete p; }); SharedPtr<string> myshared_string(mystring, [](string *p) { DebugDelete()(p); }); std::cout << *myshared_string.get() << std::endl; std::cout << "Test Copy assiment" << std::endl; SharedPtr<string> myshared_string3(new string("55555")); myshared_string3 = myshared_string; std::cout << "Test Copy Construct" << std::endl; SharedPtr<string> myshared_string2(myshared_string); std::cout << myshared_string.use_count() << std::endl; } { using std::string; using std::vector; std::cout << "Test Unique Ptr" << std::endl; UniquePtr<string> s1(new string("A10086")); std::cout << *s1.get() << std::endl; UniquePtr<string, DebugDelete> s2(new string("B10086"), DebugDelete()); std::cout << *s1.get() << std::endl; } while (1) ; return 0; }

16.29#

16.30#

Copy
// 修改你的Blob类,用你的shared_ptr 替代标准库的版本 // 这里不能使用weak_ptr了,应该自己再做一个, // 在赋值迭代器的时候,weak_ptr 的赋值操作没有对 我们自己实现的 重载 // 这里我们修改Blob 不使用迭代器了 // 16.24 为你的Blob添加一个构造函数支持两个迭代器 // 16.12 编写你自己的 Blob 和 BlobPtr 模版,包含书中未定义的多个const成员 #include <vector> #include <memory> #include <string> #include <list> #include <iostream> #include <initializer_list> #include <exception> #include <algorithm> template <class T> class SharedPtr { using DelFuncPtr = void (*)(T *); private: T *ptr_ = nullptr; size_t *count_ptr_ = nullptr; DelFuncPtr del_ = nullptr; public: SharedPtr(T *ptr = nullptr, DelFuncPtr del = nullptr) : ptr_(ptr), del_(del), count_ptr_(new size_t(ptr_ != nullptr)) {} SharedPtr(const SharedPtr &s) : ptr_(s.ptr_), del_(s.del_), count_ptr_(s.count_ptr_) { ++*s.count_ptr_; } SharedPtr &operator=(SharedPtr s) //这里使用值传递,会先复制一份 { //交换自己和临时的,临时的在退出的时候会自动调用析构释放 swap(s); return *this; } void reset(T *ptr = nullptr, DelFuncPtr d = nullptr) { auto news = SharedPtr(ptr, d); swap(news); } void swap(SharedPtr &r) noexcept { using std::swap; swap(ptr_, r.ptr_); swap(count_ptr_, r.count_ptr_); swap(del_, r.del_); } ~SharedPtr() { if (ptr_ == nullptr) return; if (0 == --*count_ptr_) { del_ == nullptr ? delete (ptr_) : del_(ptr_); delete count_ptr_; } ptr_ = nullptr; count_ptr_ = nullptr; } T *get() const noexcept { return ptr_; } size_t use_count() const noexcept { return *count_ptr_; } T &operator*() const noexcept { return *ptr_; } T *operator->() const noexcept { return ptr_; } //检查 *this 是否存储非空指针,即是否有 get() != nullptr explicit operator bool() const noexcept { return get() != nullptr; } }; template <typename T> class Blob; template <typename T> bool operator==(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator!=(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator<(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator>(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator<=(const Blob<T> &a, const Blob<T> &b); template <typename T> bool operator>=(const Blob<T> &a, const Blob<T> &b); template <typename T> class Blob { friend bool operator==<T>(const Blob<T> &a, const Blob<T> &b); friend bool operator!=<T>(const Blob<T> &a, const Blob<T> &b); // clang-format off friend bool operator< <T>(const Blob<T> &a, const Blob<T> &b); friend bool operator> <T>(const Blob<T> &a, const Blob<T> &b); // clang-format on friend bool operator<=<T>(const Blob<T> &a, const Blob<T> &b); friend bool operator>=<T>(const Blob<T> &a, const Blob<T> &b); // 以下两个应该是为了外部方便获取类型 typedef T value_type; typedef typename std::vector<T>::size_type size_type; private: SharedPtr<std::vector<T>> data; void check(size_type i, const std::string &msg) const; public: Blob() : data(new std::vector<T>()) {} // 16.24 template <typename type_it> Blob(type_it a, type_it b) : data(new std::vector<T>(a, b)) {} Blob(const Blob<T> &s) : data(new std::vector<T>(*s.data)) {} Blob(Blob<T> &&a) noexcept : data(std::move(a.data)) {} Blob &operator=(const Blob<T> &s); Blob &operator=(Blob<T> &&) noexcept; Blob(std::initializer_list<T> il) : data(new std::vector<T>(il)) {} size_type size() const { return data->size(); } bool empty() const { return data->empty(); } void push_back(T &val) { data->push_back(val); }; void push_back(const T &val) { data->push_back(std::move(val)); } void pop_back(); T &back(); const T &back() const; T &front(); const T &front() const; T &operator[](size_type i); const T &operator[](size_type i) const; void print(std::ostream &o); }; template <typename T> Blob<T> &Blob<T>::operator=(const Blob<T> &s) { data = new std::vector<T>(*s.data); return *this; } template <typename T> Blob<T> &Blob<T>::operator=(Blob<T> &&s) noexcept { if (this != s) { data = std::move(s.data); s.data = nullptr; } return *this; } template <typename T> void Blob<T>::print(std::ostream &o) { for (auto ch : (*data)) o << ch << ","; o << std::endl; } template <typename T> void Blob<T>::check(size_type i, const std::string &msg) const { if (i >= size()) { throw std::out_of_range(msg); } } template <typename T> void Blob<T>::pop_back() { check(0, "empty to pop_back"); data->pop_back(); } template <typename T> T &Blob<T>::back() { check(0, "Get empty Back()"); return data->back(); } template <typename T> const T &Blob<T>::back() const { check(0, "Get empty Back()"); return data->back(); } template <typename T> T &Blob<T>::front() { check(0, "Get empty front()"); return data->front(); } template <typename T> const T &Blob<T>::front() const { check(0, "Get empty front()"); return data->front(); } template <typename T> T &Blob<T>::operator[](size_type i) { check(i, "Get [" + std::to_string(i) + "]"); return data->at(i); } template <typename T> const T &Blob<T>::operator[](size_type i) const { check(i, "Get [" + std::to_string(i) + "]"); return data->at(i); } //**************************************************************************** template <typename T> bool operator==(const Blob<T> &a, const Blob<T> &b) { return (*a.data == *b.data); } template <typename T> bool operator!=(const Blob<T> &a, const Blob<T> &b) { return !(a == b); } template <typename T> bool operator<(const Blob<T> &a, const Blob<T> &b) { return std::lexicographical_compare(a.data->begin(), a.data->end(), b.data->begin(), b.data->end()); } template <typename T> bool operator>(const Blob<T> &a, const Blob<T> &b) { return (b < a); } template <typename T> bool operator<=(const Blob<T> &a, const Blob<T> &b) { return !(b > a); } template <typename T> bool operator>=(const Blob<T> &a, const Blob<T> &b) { return !(a < b); } int main(int argc, const char **argv) { Blob<std::string> blob_s({"1", "2"}); blob_s.print(std::cout); while (1) ; return 0; }

16.31#

Copy
// 16.31 如果我们将DebugDelete 与 unique_ptr 一起使用,解释编译器将删除器处理为内联形式的可能? // The compiler will set the default deleter type as `DebugDelete`, // which will be executed is known at compile time. 编译的时候就传递赋值

16.32#

Copy
// 在模版实参推断过程中发生了什么? 1. 类型推导 2. 实例化函数

16.33#

Copy
指出在模版实参推断过程中允许对函数实参进行的两种类型转换。 1. const转换, 实参是非const的传递给形参是const2. 数组或函数转换为指针,注意:形参不能是引用,形参是引用,传递的是数组,含有纬度的

16.34#

Copy
对下面的代码解释每个调用是否合法。如果合法,T 的类型是什么?如果不合法,为什么? template <class T> int compare(const T&, const T&); (a) compare("hi", "world"); (b) compare("bye", "dad"); a. 不合法,这里传递的是char(&a)[3] char(&a)[6] b. 合法

13.35#

Copy
13.35 下面调用中哪些是错误的(如果有的话)?如果调用合法,T 的类型是什么?如果调用不合法,问题何在? template <typename T> T calc(T, int); tempalte <typename T> T fcn(T, T); double d; float f; char c; (a) calc(c, 'c'); (b) calc(d, f); (c) fcn(c, 'c'); (d) fcn(d, f); a. 合法, T=char b. 合法,T=double c 合法 char, d 不合法,不能发生类型转换

16.36#

Copy
// 进行下面的调用会发生什么 template <typename T> f1(T, T); template <typename T1, typename T2) f2(T1, T2); int i = 0, j = 42, *p1 = &i, *p2 = &j; const int *cp1 = &i, *cp2 = &j; (a) f1(p1, p2); (b) f2(p1, p2); (c) f1(cp1, cp2); (d) f2(cp1, cp2); (e) f1(p1, cp1); (f) f2(p1, cp1); // f1没有返回值 哈哈哈 a. f1(int*,int*); b. f2(int*,int*); c. f1(const int*,const int*); d. f2(const int*,const int*); e. error f. f2( int*,const int*);

16.37#

Copy
标准库 max 函数有两个参数,它返回实参中的较大者。此函数有一个模版类型参数。 你能在调用 max 时传递给它一个 int 和一个 double 吗?如果可以,如何做?如果不可以,为什么? 指定参数类型 max<double>(a, b); #include <iostream> #include <string> #include <algorithm> using namespace std; int main(int argc, char const *argv[]) { int a = 6; double b = 6.1231; std::cout << std::max<long double>(a, b) << std::endl; // initializer_list<T> 也是模版,不会发生转换 //std::cout << std::max({a, b}, [](const int a, const int b) { return a < b; }) << std::endl; std::cout << std::max({1, 2}, [](const int a, const int b) { return a < b; }) << std::endl; while (1) ; return 0; }

16.38#

Copy
当我们调用 make_shared 时,必须提供一个显示模版实参。解释为什么需要显式模版实参以及它是如果使用的。 返回类型无法推断

16.39#

Copy
16.1.1578 中的原始版本的 compare 函数,使用一个显式模版实参,使得可以向函数传递两个字符串字面量。 compare<std::string>("a", "bb");

16.40#

Copy
下面的函数是否合法?如果不合法,为什么?如果合法,对可以传递的实参类型有什么限制(如果有的话)? 返回类型是什么? 合法,元素支持+ 返回类型由operator+决定 template <typename It> auto fcn3(It beg, It end) -> decltype(*beg + 0) { //处理序列 return *beg; }

16.41#

Copy
编写一个新的 sum 版本,它返回类型保证足够大,足以容纳加法结果 template <typename T1, typename T2> auto sum(T1 a, T2 b) -> decltype(a + b) { return a + b; }

16.42#

Copy
// 对下面每个调用,确定 T 和 val 的类型: template <typename T> void g(T&& val); int i = 0; const int ci = i; (a) g(i); (b) g(ci); (c) g(i * ci); a. i是左值,所以会传递左值引用 int& && 折叠为 int& b. ci 是const int, 折叠为const int& c. i*ci是一个局部的变量,是个右值int&& 折叠为int&&

16.43#

Copy
使用上一题定义的函数,如果我们调用g(i = ci),g 的模版参数将是什么? i=ci 返回的是 i 也就是 int,折叠为int& #include <iostream> int main(int argc, char const *argv[]) { int i = 0; ++(i = 3); std::cout << i << std::endl; //4 while (1) ; return 0; }

16.44#

Copy
使用与第一题中相同的三个调用,如果 g 的函数参数声明为 T(而不是T&&),确定T的类型。 如果g的函数参数是 const T&呢? template <typename T> void g(T val); int i = 0; const int ci = i; (a) g(i); int (b) g(ci); int (c) g(i * ci); int template <typename T> void g(const& val); int i = 0; const int ci = i; (a) g(i); int (b) g(ci); int (c) g(i * ci); int

16.45#

Copy
如果下面的模版,如果我们对一个像42这样的字面常量调用g,解释会发生什么? 如果我们对一个int 类型的变量调用g 呢? template <typename T> void g(T&& val) { vector<T> v; } g(42) 传递的就是 int&& { vector<int&&> v; } int i; g(i) // 传递是 int& && 折叠为 int& { vector<int&> v; //报错,无法保存引用 }

16.46#

Copy
// 解释下面的循环,它来自13.5节中的 StrVec::reallocate: // alloc.construct(dest++, std::move(*elem++)); // *elem 为左值,转换为 elem的右值 template< class U, class... Args > void construct( U* p, Args&&... args );

16.47#

Copy
#include <iostream> void f(int v1, int &v2) { std::cout << v1 << " " << ++v2 << std::endl; } void g(int &&i, int &j) { std::cout << i << " " << ++j << std::endl; } template <typename F, typename T1, typename T2> void flip(F f, T1 &&t1, T2 &&t2) { f(std::forward<T2>(t2), std::forward<T1>(t1)); } int main() { int j = 0; flip(f, j, 42); flip(g, j, 42); while (1) ; }

16.48#

Copy
// 16.48 编写你自己版本的 debug_rep 函数。 #include <iostream> #include <string> #include <sstream> using std::string; template <typename T> string debug_rep(const T &t) { std::ostringstream ret; ret << t; return ret.str(); } template <typename T> string debug_rep(T *t) { std::ostringstream ret; ret << "Point Addr=" << t; if (t == nullptr) ret << "nullptr"; else ret << debug_rep(*t); return ret.str(); } string debug_rep(const string &t) { return "String:" + t; } string debug_rep(char *t) { return "char*" + debug_rep(string(t)); } string debug_rep(const char *t) { return "const char*" + debug_rep(string(t)); } int main(int argc, const char **argv) { std::cout << debug_rep("123456") << std::endl; while (1) ; return 0; }

16.49#

Copy
//16.49解释下面每个调用会发生什么 template <typename T> void f(T); template <typename T> void f(const T*); template <typename T> void g(T); template <typename T> void g(T*); 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); g(42) T=int 3.template <typename T> void g(T); g(p) T=int 4.template <typename T> void g(T*); g(ci) T=const int 3.template <typename T> void g(T); g(p2) T=const int 4.template <typename T> void g(T*); f(42) T=int 1.template <typename T> void f(T); f(p) T=int* 1.template <typename T> void f(T); f(ci) T=const int 1.template <typename T> void f(T); f(p2) T=int 2.template <typename T> void f(const T*);

16.50#

Copy
// 16.50 定义上一个练习中的函数,令它们打印一条身份信息。运行该练习中的代码。如果函数调用的行为与你预期不符,确定你理解了原因。 /* template <typename T> void f(T); template <typename T> void f(const T*); template <typename T> void g(T); template <typename T> void g(T*); 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); g(42) T=int 3.template <typename T> void g(T); g(p) T=int 4.template <typename T> void g(T*); g(ci) T=const int 3.template <typename T> void g(T); g(p2) T=const int 4.template <typename T> void g(T*); f(42) T=int 1.template <typename T> void f(T); f(p) T=int* 1.template <typename T> void f(T); f(ci) T=const int 1.template <typename T> void f(T); f(p2) T=int 2.template <typename T> void f(const T*); */ #include <iostream> #include <string> template <typename T> void f(T) { std::cout << "1" << std::endl; } template <typename T> void f(const T *) { std::cout << "2" << std::endl; } template <typename T> void g(T) { std::cout << "3" << std::endl; } template <typename T> void g(T *) { std::cout << "4" << std::endl; } int main(int argc, char const *argv[]) { 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); while (1) ; return 0; }

16.51#

16.52#

Copy
// 16.51 调用本节中的每个 foo,确定 sizeof…(Args) 和 sizeof…(rest)分别返回什么。 #include <iostream> using namespace std; template <typename T, typename... Args> void foo(const T &t, const Args &... rest) { std::cout << "sizeof...(Args)=" << sizeof...(Args) << " sizeof...(rest)=" << sizeof...(rest) << std::endl; } int main(int argc, const char **argv) { int i = 0; double d = 3.14; string s = "how"; 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 foo(i, s, s, d); /// sizeof...(Args)=3 sizeof...(rest)=3 while (1) ; return 0; }

16.53#

Copy
// 16.53 编写你自己版本的 print 函数,并打印一个、两个及五个实参来测试它,要打印的每个实参都应有不同的类型。 #include <iostream> using namespace std; template <typename T> ostream &print(ostream &o, const T &s) { return o << s << endl; } template <typename A, typename... T> ostream &print(ostream &o, const A &a, const T &... s) { o << a << ","; return print(o, s...); } int main(int argc, const char **argv) { int i = 1; double d = 3.14; float f = 99.99; string s = "hello"; print(std::cout, i); print(std::cout, i, s); print(std::cout, i, d, f, s, "123456"); while (1) ; return 0; }

16.54#

Copy
如果我们对一个没 << 运算符的类型调用 print,会发生什么? 编译实例化失败. //no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'const std::vector<int>') //print(std::cout, i, d, f, s, vector<int>(1));

16.55#

Copy
// 如果我们的可变参数版本 print 的定义之后声明非可变参数版本,解释可变参数的版本会如何执行。 我们最终会执行到只有 ostream,没有第二个参数 print(std::ostream&) 但是我们的模版函数是 ostream &print(ostream &o, const A &a, const T &... s) 也就是没有匹配一个参数的版本

16.56#

Copy
// 16.56 编写并测试可变参数版本的 errorMsg。 #include <initializer_list> #include <iostream> #include <string> #include <sstream> using namespace std; /*********************************************************************/ template <typename T> string debug_rep(const T &t) { std::ostringstream ret; ret << t; return ret.str(); } template <typename T> string debug_rep(T *t) { std::ostringstream ret; ret << "Point Addr=" << t; if (t == nullptr) ret << "nullptr"; else ret << debug_rep(*t); return ret.str(); } string debug_rep(const string &t) { return "String:" + t; } string debug_rep(char *t) { return "char*" + debug_rep(string(t)); } string debug_rep(const char *t) { return "const char*" + debug_rep(string(t)); } /*********************************************************************/ void err_msg_old(initializer_list<string> il) { for (auto ch : il) std::cout << ch << ","; std::cout << std::endl; } template <typename T> ostream &print(ostream &o, const T &s) { return o << s << endl; } template <typename A, typename... T> ostream &print(ostream &o, const A &a, const T &... s) { o << a << ","; return print(o, s...); } template <typename... T> ostream &err_msg(ostream &o = std::cout, const T &... s) { // 这里会展开 debug_rep(int) debug_rep(char) return print(o, debug_rep(s)...); } int main(int argc, char const *argv[]) { err_msg_old({"1", "2", "3"}); err_msg(std::cout, "1", 1, 3.14); while (1) ; return 0; }

16.57#

Copy
可变参数的比较灵活,但是要用比较多的堆栈估计 简单版本的,代码简单,方便调试

16.58#

Copy
// 16.58 你的 StrVec 类及你为16.1.2节练习中编写的 Vec 类添加 emplace_back 函数。 // template< class... Args > // void emplace_back( Args&&... args ); /* template <class... Args> T *emplace_back(Args &&... args) { chk_n_alloc(); alloc.construct(first_free++, std::forward<Args>(args)...); } std::string its = "my_name_is_yer"; vec.emplace_back(its.begin(), its.end()); vec.emplace_back("back_123"); vec.emplace_back(20, 'c'); */ // 16.16 定义模版类的vec 替代之前的Strvec #include <memory> #include <algorithm> #include <utility> #include <initializer_list> #include <exception> #include <string> #include <stdexcept> #include <iostream> // using std::cin; // using std::cout; // using std::endl; // 定义一些公共操作 // 从一个迭代器范围复制 到指定的位置,返回内存的首地址和尾地址+1 也就是返回 begin和end /** 如何设计一个 vector 1. 首先我们定义一个分配器,一个首地址,尾地址,以及容量 2. 提供 size,begin,end,capacity,at,[] 3. push_back chk_n_alloc(); 3.1 检查容量的操作 3.2 容量的分配,这里需要设计一个移动函数 alloc.construct 3.3 数据构造 4. 移动函数涉及 alloc_n_move 4.1 内存分配 4.2 原来数据的移动 5.设计reserve 5.1 内存分配和移动 alloc_n_move 6.设计resize 重设容器大小以容纳 count 个元素。 若当前大小大于 count ,则减小容器为其首 count 个元素。 设置指针,调用元素的析构函数 destroy析构在已分配存储中的对象 若当前大小小于 count ,则后附额外元素,并以 value 的副本初始化。 也就是调用reserve */ template <typename> 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> &); // clang-format off friend bool operator< <T>(const Vec<T>&, const Vec<T>&); friend bool operator> <T>(const Vec<T>&, const Vec<T>&); // clang-format on friend bool operator<=<T>(const Vec<T> &, const Vec<T> &); friend bool operator>=<T>(const Vec<T> &, const Vec<T> &); private: T *elements; T *first_free; T *cap; std::allocator<T> alloc; std::pair<T *, T *> alloc_n_copy(const T *b, const T *e); void range_initialize(const T *first, const T *last); void free(); void reallocate(); void alloc_n_move(size_t new_cap); void chk_n_alloc() { if (size() == capacity()) reallocate(); } public: Vec(std::initializer_list<T>); Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} Vec(const Vec<T> &); //------------------------------------------------------------Vec<T> &operator=(const Vec<T> &s); Vec &operator=(const Vec<T> &s); Vec(Vec<T> &&) noexcept; Vec &operator=(Vec<T> &&) noexcept; T *begin() const { return elements; } T *end() const { return first_free; } T &at(size_t pos) { return *(elements + pos); } const T &at(size_t pos) const { return *(elements + pos); } T &operator[](size_t n) { return elements[n]; } const T &operator[](size_t n) const { return elements[n]; } void push_back(const T &); size_t size() const { return first_free - elements; } size_t capacity() const { return cap - elements; } void reserve(size_t new_cap); void resize(size_t count); void resize(size_t count, const T &); template <class... Args> T *emplace_back(Args &&... args) { chk_n_alloc(); alloc.construct(first_free++, std::forward<Args>(args)...); } ~Vec(); }; template <typename T> 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> void Vec<T>::range_initialize(const T *first, const T *last) { auto newdata = alloc_n_copy(first, last); elements = newdata.first; first_free = cap = newdata.second; } template <typename T> void Vec<T>::free() { if (elements) { //执行元素的析构函数 for_each(elements, first_free, [this](T &rhs) { alloc.destroy(&rhs); }); //释放vector内存 alloc.deallocate(elements, cap - elements); } } template <typename T> Vec<T>::Vec(std::initializer_list<T> il) { range_initialize(il.begin(), il.end()); } template <typename T> Vec<T>::Vec(const Vec<T> &s) { range_initialize(s.begin, s.end); } template <typename T> Vec<T> &Vec<T>::operator=(const Vec<T> &s) { if (this != s) { auto data = alloc_n_copy(s.begin(), s.end()); free(); elements = data.first; first_free = cap = data.second; } return *this; } template <typename T> Vec<T>::Vec(Vec<T> &&s) noexcept { elements = s.elements; first_free = s.first_free; cap = s.cap; s.elements = s.first_free = s.cap = nullptr; } template <typename T> Vec<T> &Vec<T>::operator=(Vec<T> &&s) noexcept { if (this != &s) { free(); elements = s.elements; first_free = s.first_free; cap = s.cap; s.elements = s.first_free = s.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; 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 + new_cap; } template <typename T> void Vec<T>::reallocate() { auto newcapacity = size() ? 2 * size() : 1; alloc_n_move(newcapacity); } template <typename T> void Vec<T>::reserve(size_t new_cap) { if (new_cap <= capacity()) return; alloc_n_move(new_cap); } // resize // 重设容器大小以容纳 count 个元素。 // 若当前大小大于 count ,则减小容器为其首 count 个元素。 // 若当前大小小于 count ,则后附额外元素,并以 value 的副本初始化。 template <typename T> void Vec<T>::resize(size_t count, const T &s) { if (count > size()) { if (count > capacity()) reserve(count * 2); for (size_t i = size(); i != count; ++i) alloc.construct(first_free++, s); } else if (count < size()) { while (first_free != elements + count) alloc.destroy(--first_free); } } template <typename T> void Vec<T>::resize(size_t count) { resize(count, T()); } template <typename T> void Vec<T>::push_back(const T &s) { chk_n_alloc(); alloc.construct(first_free++, s); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ template <typename T> bool operator==(const Vec<T> &lhs, const Vec<T> &rhs) { return (lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), 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 std::lexicographical_compare(lhs.begin(), lhs.end(), 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); } int main() { Vec<std::string> vec; vec.reserve(6); std::cout << "capacity(reserve to 6): " << vec.capacity() << std::endl; vec.reserve(4); std::cout << "capacity(reserve to 4): " << vec.capacity() << std::endl; vec.push_back("hello"); vec.push_back("world"); vec.resize(4); std::string its = "my_name_is_yer"; vec.emplace_back(its.begin(), its.end()); vec.emplace_back("back_123"); vec.emplace_back(20, 'c'); for (auto i = vec.begin(); i != vec.end(); ++i) std::cout << *i << std::endl; std::cout << "-EOF-" << std::endl; vec.resize(1); for (auto i = vec.begin(); i != vec.end(); ++i) std::cout << *i << std::endl; std::cout << "-EOF-" << std::endl; Vec<std::string> vec_list{"hello", "world", "pezy"}; for (auto i = vec_list.begin(); i != vec_list.end(); ++i) std::cout << *i << " "; std::cout << std::endl; // Test operator== const Vec<std::string> const_vec_list{"hello", "world", "pezy"}; if (vec_list == const_vec_list) for (const auto &str : const_vec_list) std::cout << str << " "; std::cout << std::endl; // Test operator< const Vec<std::string> const_vec_list_small{"hello", "pezy", "ok"}; std::cout << (const_vec_list_small < const_vec_list) << std::endl; // Test [] std::cout << const_vec_list_small[1] << std::endl; while (1) ; }

16.59#

Copy
// 假定 s 是一个 string,解释调用 svec.emplace_back(s)会发生什么 1.转发扩展包 2. s 传递是值传递,也就是会调用string newstring(s),拷贝构造函数

16.60#

Copy
// 解释 make_shared 是如何工作的。 最简单的一种重载是 template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); 我们在使用的时候, shared_ptr<string> a=make_shared<string>("123"); 1. 转发扩展包给 class T 的构造函数 2. 内部提取地址到shared<T>

16.61#

Copy
// 解释 make_shared 是如何工作的。 // 最简单的一种重载是 // template< class T, class... Args > // shared_ptr<T> make_shared( Args&&... args ); // 我们在使用的时候, shared_ptr<string> a=make_shared<string>("123"); // 1. 转发扩展包给 class T 的构造函数 // 2. 内部提取地址到shared<T> #include <memory> #include <string> #include <iostream> using namespace std; template <class T, class... Args> shared_ptr<T> my_make_shared(Args &&... args) { shared_ptr<T> ret(new T(std::forward<Args>(args)...)); return ret; } int main(int argc, char const *argv[]) { shared_ptr<string> s1 = my_make_shared<string>("123"); std::cout << *s1 << std::endl; while (1) ; return 0; }

16.62#

Copy
// 16.62 定义你自己版本的 hash<Sales_data>, 并定义一个 Sales_data 对象的 unorder_multise。将多条交易记录保存到容器中,并打印其内容 // p396 // 无序容器需要提供 元素的== 以及哈希函数 // 需要提供hash<类型>的模版,一个 ()运算返回size_t 表示hash值 #include <string> #include <vector> #include <iostream> #include <unordered_set> using namespace std; class Sales_data { friend bool operator==(const Sales_data &, const Sales_data &); friend std::hash<Sales_data>; private: string isbn; unsigned units_sold = 0; double revenue = 0.0; public: Sales_data(string isbn, unsigned units_sold, double revenue) : isbn(isbn), units_sold(units_sold), revenue(revenue) {} double avg_price() { return revenue / units_sold; } void print() { std::cout << "name=" << isbn << " aver_price= " << avg_price() << std::endl; } string prints() { return string("name=") + isbn + " aver_price= " + to_string(avg_price()); } }; bool operator==(const Sales_data &a, const Sales_data &b) { return (a.isbn == b.isbn) && (a.revenue == b.revenue) && (a.units_sold == b.units_sold); } 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.isbn) ^ hash<unsigned>()(s.units_sold) ^ hash<double>()(s.revenue); } }; } // namespace std int main(int argc, const char **argv) { Sales_data A1("A1", 5, 17); A1.print(); std::unordered_multiset<Sales_data> mset; mset.emplace(A1); mset.emplace("C++ Primer", 5, 9.99); for (auto ch : mset) std::cout << "hash()=" << std::hex << std::hash<Sales_data>()(ch) << ch.prints() << std::endl; while (1) ; return 0; }

16.63#

16.64#

Copy
// 16.64 为上一题的模版编写特例化版本来处理vector<const char*>。编写程序使用这个特例化版本。 // 16.63 定义一个函数模版,统计一个给定值在一个vecor中出现的次数。 // 测试你的函数,分别传递给它一个double的vector,一个int的vector以及一个string的vector。 #include <algorithm> #include <string> #include <iostream> #include <vector> using namespace std; template <typename T> int GetCount(T elem, const vector<T> &v) { std::cout << __LINE__ << " :GetCount(T elem, const vector<T> &v)" << std::endl; int i = 0; for (auto ch : v) { if (ch == elem) i++; } return i; } template <> int GetCount(const char *elem, const vector<const char *> &v) { std::cout << __LINE__ << " :GetCount(const char *elem, const vector<const char *> &v)" << std::endl; int i = 0; for (auto ch : v) { if (string(ch) == string(elem)) i++; } return i; } int GetCount(const char *elem, const vector<string> &v) { std::cout << __LINE__ << " :GetCount(const char *elem, const vector<string> &v)" << std::endl; return GetCount(string(elem), v); } int GetCount(const int elem, const vector<double> &v) { return GetCount((double)elem, v); } int main(int argc, char const *argv[]) { vector<string> s({"123", "456", "789", "123", "222"}); std::cout << GetCount("123", s) << std::endl; std::cout << GetCount(string("123"), s) << std::endl; vector<int> i = {1, 2, 3, 4, 5, 6, 1, 2}; std::cout << GetCount(1, i) << std::endl; // vector<double> d = {1.0, 2.5, 3, 4, 5, 6, 1, 2}; // std::cout << GetCount(1, d) << std::endl; vector<const char *> s3({"123", "456", "789", "123", "222"}); std::cout << GetCount("123", s3) << std::endl; while (1) ; return 0; }

16.65#

Copy
// 在16.3节中我们定义了两个重载的 debug_rep 版本,一个接受 const char* 参数,另一个接受 char * 参数。将这两个函数重写为特例化版本。 // 16.48 编写你自己版本的 debug_rep 函数。 #include <iostream> #include <string> #include <sstream> using std::string; string debug_rep(const string &t) { return "String:" + t; } template <typename T> string debug_rep(const T &t) { std::ostringstream ret; ret << t; return ret.str(); } template <typename T> string debug_rep(T *t) { std::ostringstream ret; ret << "Point Addr=" << t; if (t == nullptr) ret << "nullptr"; else ret << debug_rep(*t); return ret.str(); } template <> string debug_rep(const char *t) { return string("const char*") + debug_rep(string(t)); } template <> string debug_rep(char *t) { return "char*" + debug_rep(string(t)); } // string debug_rep(const char *t) // { // return "const char*" + debug_rep(string(t)); // } int main(int argc, const char **argv) { std::cout << debug_rep("123456") << std::endl; while (1) ; return 0; }

16.66#

Copy
重载debug_rep 函数与特例化它相比,有何优点和缺点? 特例化是的本质是实例化一个模版,不影响函数匹配. 而重载如果有非模版的,直接使用该版本 重载会改变函数匹配顺序,因为增加了新函数 几个函数都提供同样好的匹配的情况下,编译器会选择非板版本

16.67#

Copy
定义特例化版本会影响 debug_rep 的函数匹配吗?如果不影响,为什么? 不会改变,特例化模板函数不会重载函数,不会影响函数匹配顺序 也就是不产生新的函数类型
Copy
> p262 特例化是的本质是实例化一个模版,不影响函数匹配. 而重载如果有非模版的,直接使用该版本 也就是他的匹配顺序是模版的顺序,模版之后下面来找具体的特例化(**可以理解为先匹配模版后才能匹配特例化**) 而一个重载和一个模版是平等关系的 ​```cpp 重载的版本(包括模版)-------------模版 | |~~~~~~~~~~~~~~~| 特例化 通用的模版实现

posted @   zongzi10010  阅读(188)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
CONTENTS