From 017be2b560dc9dc04b486e86c893934b5f25c7e9 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Wed, 20 Mar 2019 14:33:48 +0800 Subject: [PATCH 01/16] Add answer to ex_16_54 --- ch16/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ch16/README.md b/ch16/README.md index d42cd9cf..3df428f8 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -467,6 +467,7 @@ f(p2); // type: const int * call template 2 T:int instantiation: vo ``` ## Exercise 16.50 + > Define the functions from the previous exercise so that they print an identifying message. Run the code from that exercise. If the calls behave differently from what you expected, make sure you understand why. [overload template](ex16_50_overload_template.cpp) @@ -486,7 +487,21 @@ foo(i, s, s, d); // input in Args: string, string, double sizeof...(Args ``` # Exercise 16.52 + > Write a program to check your answer to the previous question. [variadic template](ex16_52_variadic_template.cpp) +# Exercise 16.54 + +> What happens if we call print on a type that doesn’t have an << operator? + +Error: +```cpp +std::vector v = {1, 2}; +print(v); +// error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream}’ +// and const std::vector’) +// return os << t << endl; +``` + From b6f4735106594190fc99f68a055f664d87296372 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Wed, 20 Mar 2019 14:36:36 +0800 Subject: [PATCH 02/16] Add answer code for exercise 16.53 --- ch16/ex16_53_print.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 ch16/ex16_53_print.cpp diff --git a/ch16/ex16_53_print.cpp b/ch16/ex16_53_print.cpp new file mode 100644 index 00000000..638395a3 --- /dev/null +++ b/ch16/ex16_53_print.cpp @@ -0,0 +1,36 @@ +#include +#include + +using std::ostream; +using std::cout; +using std::endl; +using std::string; + +template +ostream & print(ostream & os, const T & t) +{ + return os << t << endl; +} + +template +ostream & print(ostream & os, const T & t, const Args& ... rest) +{ + os << t << ", "; + return print(os, rest...); + +} + + +int main() +{ + int i = 2; + double d = 1.23123; + char c = 'c'; + string s = "this is a string"; + cout << "print(cout, i) : " << endl; + print(cout, i); + cout << "print(cout, d, s) : " << endl; + print(cout, d, s); + cout << "print(cout, i, d, s, c, \"this is a C string\") : " << endl; + print(cout, i, d, s, c, "this is a C string"); +} From 6002672fd4241b889b0b2373bd9a9f7c92807fa6 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 13:48:36 +0800 Subject: [PATCH 03/16] add answer code for ex_16_58 add answer code for ex_16_58 --- ch16/ex16_58_emplace.cpp | 330 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 ch16/ex16_58_emplace.cpp diff --git a/ch16/ex16_58_emplace.cpp b/ch16/ex16_58_emplace.cpp new file mode 100644 index 00000000..700046c6 --- /dev/null +++ b/ch16/ex16_58_emplace.cpp @@ -0,0 +1,330 @@ +#ifndef VC_H +#define VC_H + +#include +#include +#include +#include + +using std::allocator; +using std::uninitialized_copy; +using std::ostream; +using std::cout; +using std::cerr; +using std::endl; +using std::for_each; +using std::swap; +using std::string; +using std::pair; +using std::initializer_list; + +template class Vec; + +template bool operator==(const Vec &, const Vec &); +template bool operator!=(const Vec &, const Vec &); +template bool operator< (const Vec &, const Vec &); +template bool operator> (const Vec &, const Vec &); +template bool operator<=(const Vec &, const Vec &); +template bool operator>=(const Vec &, const Vec &); + + +template +class Vec +{ + friend bool operator==(const Vec &, const Vec &); + friend bool operator!=(const Vec &, const Vec &); + friend bool operator< (const Vec &, const Vec &); + friend bool operator> (const Vec &, const Vec &); + friend bool operator<=(const Vec &, const Vec &); + friend bool operator>=(const Vec &, const Vec &); + + public: + Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} + Vec(initializer_list); + Vec(const Vec &); + Vec(Vec &&) noexcept; + Vec & operator=(const Vec &); + Vec & operator=(Vec &&) noexcept; + ~Vec() noexcept; + + void push_back(const T &); + void push_back(T &&); + size_t size() const; + size_t capacity() const; + T * begin() const; + T * end() const; + void reserve(size_t); + void resize(size_t, const T & val = T()); + void free(); + T & operator[](size_t); + const T & operator[](size_t) const; + + template + void emplace_back(Args && ...); + void swap(Vec &) noexcept; + private: + static allocator alloc; + T * elements; + T * first_free; + T * cap; + pair alloc_n_copy(const T * const &, const T * const &); + void chk_n_alloc(); + void reallocate(size_t max=0); +}; + +template +allocator Vec::alloc; + +template +inline Vec::Vec(initializer_list init_l) : Vec() +{ + pair p = alloc_n_copy(init_l.begin(), init_l.end()); + elements = p.first; + first_free = cap = p.second; +} + +template +inline Vec::Vec(const Vec & v) +{ + pair p = alloc_n_copy(v.begin(), v.end()); + elements = p.first; + first_free = cap = p.second; +} + +template +inline Vec::Vec(Vec && v) noexcept : elements(v.elements), first_free(v.first_free), cap(v.cap) +{ + v.elements = v.first_free = v.cap = nullptr; +} + +template +inline Vec & Vec::operator=(const Vec & v) +{ + if (this != &v) + { + free(); + pair p = alloc_n_copy(v.begin(), v.end()); + elements = p.first; + first_free = cap = p.second; + } + return *this; +} + +template +inline Vec & Vec::operator=(Vec && v) noexcept +{ + if (this != &v) + { + free(); + swap(v); + } + return *this; +} + +template +inline Vec::~Vec() noexcept +{ + if (elements && first_free && cap) + free(); +} + +template +inline void Vec::push_back(const T & t) +{ + chk_n_alloc(); + alloc.construct(first_free++, t); +} + +template +inline void Vec::push_back(T && t) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::move(t)); +} + +template +inline size_t Vec::size() const +{ + return first_free - elements; +} + +template +inline size_t Vec::capacity() const +{ + return cap - elements; +} + +template +inline T * Vec::begin() const +{ + return elements; +} + +template +inline T * Vec::end() const +{ + return first_free; +} + +template +inline void Vec::reserve(size_t n) +{ + if (n > capacity()) + reallocate(n); +} + +template +void Vec::resize(size_t n, const T & val) +{ + if (n < size()) + { + while (first_free != elements + n) + alloc.destroy(--first_free); + } + else + { + if (n > capacity()) + reserve(n); + while (first_free != elements + n) + alloc.construct(first_free++, val); + } +} + +template +void Vec::free() +{ + for_each(first_free, first_free, [](T & t) {alloc.destroy(&t);}); + alloc.deallocate(elements, cap - elements); + elements = first_free = cap = nullptr; +} + +template +inline T & Vec::operator[](size_t index) +{ + if (index > 0 && index < size()) + return *(elements + index); + else + cerr << "Index error:\nmax_index: " << size() - 1 + << " input index: " << index << endl; + exit(EXIT_FAILURE); +} +template +inline const T & Vec::operator[](size_t index) const +{ + if (index > 0 && index < size()) + return *(elements + index); + else + cerr << "Index error:\nmax_index: " << size() - 1 + << " input index: " << index << endl; + exit(EXIT_FAILURE); +} + +template +template +inline void Vec::emplace_back(Args && ... args) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::forward(args)...); +} + +template +inline pair Vec::alloc_n_copy(const T * const & st, const T * const & end) +{ + T * start = alloc.allocate(end - st); + return {start, uninitialized_copy(st, end, start)}; +} + +template +inline void Vec::chk_n_alloc() +{ + if (size() == capacity()) + reallocate(); +} + +template +void Vec::reallocate(size_t max) +{ + size_t newcapacity = max ? 2 * max : (size() ? 2 * size() : 1); + T * newstart = alloc.allocate(newcapacity); + T * dest = newstart; + for_each(elements, first_free, [&dest](T & elem) {alloc.construct(dest++, std::move(elem));}); + free(); + elements = newstart; + first_free = dest; + cap = newstart + newcapacity; +} + +template +inline void Vec::swap(Vec & v) noexcept +{ + std::swap(elements, v.elements); + std::swap(first_free, v.first_free); + std::swap(cap, v.cap); +} + +template +bool operator==(const Vec & v1, const Vec & v2) +{ + return v1.size() == v2.size() && std::equal(v1.begin(), v1.end(), v2.begin()); +} + +template +inline bool operator!=(const Vec & v1, const Vec & v2) +{ + return !(v1 == v2); +} + +template +bool operator<(const Vec & v1, const Vec & v2) +{ + return std::lexicographical_compare(v1.begin(), v1.end(), v2.begin(), v2.end()); +} + +template +bool operator>(const Vec & v1, const Vec & v2) +{ + return v2 < v1; +} + +template +bool operator<=(const Vec & v1, const Vec & v2) +{ + return !(v2 < v1); +} + +template +bool operator>=(const Vec & v1, const Vec & v2) +{ + return !(v1 < v2); +} + + + + +int main() +{ + // construc and move. + Vec a = {1, 2, 3, 4, 5, 6, 7}; + for_each(a.begin(), a.end(), [](const int & i) {cout << i << endl;}); + Vec b(std::move(a)); + b.push_back(8); + for_each(b.begin(), b.end(), [](const int & i) {cout << i << endl;}); + Vec c = std::move(b); + + // resize. + c.resize(10); + for_each(c.begin(), c.end(), [](const int & i) {cout << i << endl;}); + + // emplace. + c.emplace_back(4); + for_each(c.begin(), c.end(), [](const int & i) {cout << i << endl;}); + + Vec vs; + vs.push_back("first string"); + vs.emplace_back(10, 'c'); + for_each(vs.begin(), vs.end(), [](const string & i) {cout << i << endl;}); +} + +#endif + + From aff273aeb4d8a3c7e556ff9b00387d77f35f3174 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 16:09:24 +0800 Subject: [PATCH 04/16] Add answer for exercise 16.59 --- ch16/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ch16/README.md b/ch16/README.md index 3df428f8..4fb611b3 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -505,3 +505,30 @@ print(v); // return os << t << endl; ``` +# Exercise 16.58 + +> Write the emplace_back function for your StrVec class and for the Vec class that you wrote for the exercises in 16.1.2 (p. 668). + +[emplace_back](ex16_58_emplace.cpp) + +# Exercise 16.59 + +> Assuming s is a string, explain svec.emplace_back(s). + +```cpp +template +template +inline void Vec::emplace_back(Args && ... args) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::forward(args)...); +} +Vec vs; +std::string s = "asd"; +vs.emplace_back(s); +// Think (Args && ... args) as (T && t) for only one parameter is passed to Args. +// 1: T is reduced as (int &) and type of function parameter t(int & &&) collapse to (int &) (see Exercise 16.42). +// 2: std::forward(t) add && to T: int & -> int & && collapse to (int &). +// 3: call copy constructor of std::string because second parameter is a lvalue. +``` + From 11ebeda4b02cc09c1c2bfa96a4ac156ab1f9bd43 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 16:19:53 +0800 Subject: [PATCH 05/16] Update README.md --- ch16/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ch16/README.md b/ch16/README.md index 4fb611b3..be6b511d 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -526,9 +526,9 @@ inline void Vec::emplace_back(Args && ... args) Vec vs; std::string s = "asd"; vs.emplace_back(s); -// Think (Args && ... args) as (T && t) for only one parameter is passed to Args. +// Think (Args && ... args) as (T && t) for only one parameter is passed to the template parameter pack. // 1: T is reduced as (int &) and type of function parameter t(int & &&) collapse to (int &) (see Exercise 16.42). -// 2: std::forward(t) add && to T: int & -> int & && collapse to (int &). -// 3: call copy constructor of std::string because second parameter is a lvalue. +// 2: std::forward(t) returns type (T &&): (int &) -> (int & &&) collapse to (int &). +// 3: call copy constructor of std::string because the second parameter is a lvalue. ``` From e5e76d868f0884a251f343934ddf7539e4636eea Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 16:37:23 +0800 Subject: [PATCH 06/16] Update README.md --- ch16/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ch16/README.md b/ch16/README.md index be6b511d..86712418 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -527,8 +527,8 @@ Vec vs; std::string s = "asd"; vs.emplace_back(s); // Think (Args && ... args) as (T && t) for only one parameter is passed to the template parameter pack. -// 1: T is reduced as (int &) and type of function parameter t(int & &&) collapse to (int &) (see Exercise 16.42). +// 1: T is deduced as (int &). see Exercise 16.42. // 2: std::forward(t) returns type (T &&): (int &) -> (int & &&) collapse to (int &). -// 3: call copy constructor of std::string because the second parameter is a lvalue. +// 3: call copy constructor of std::string because the second parameter's type is lvalue reference(int &). ``` From 1b045388fa6efa6b3a71a725771ac622b76cdd56 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 18:42:34 +0800 Subject: [PATCH 07/16] Update ex16_58_emplace.cpp --- ch16/ex16_58_emplace.cpp | 94 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/ch16/ex16_58_emplace.cpp b/ch16/ex16_58_emplace.cpp index 700046c6..06f873dc 100644 --- a/ch16/ex16_58_emplace.cpp +++ b/ch16/ex16_58_emplace.cpp @@ -46,18 +46,18 @@ class Vec Vec & operator=(const Vec &); Vec & operator=(Vec &&) noexcept; ~Vec() noexcept; - - void push_back(const T &); - void push_back(T &&); - size_t size() const; - size_t capacity() const; + T * begin() const; T * end() const; + size_t size() const; + size_t capacity() const; + T & operator[](size_t); + const T & operator[](size_t) const; + void push_back(const T &); + void push_back(T &&); void reserve(size_t); void resize(size_t, const T & val = T()); void free(); - T & operator[](size_t); - const T & operator[](size_t) const; template void emplace_back(Args && ...); @@ -129,17 +129,15 @@ inline Vec::~Vec() noexcept } template -inline void Vec::push_back(const T & t) +inline T * Vec::begin() const { - chk_n_alloc(); - alloc.construct(first_free++, t); + return elements; } template -inline void Vec::push_back(T && t) +inline T * Vec::end() const { - chk_n_alloc(); - alloc.construct(first_free++, std::move(t)); + return first_free; } template @@ -155,15 +153,38 @@ inline size_t Vec::capacity() const } template -inline T * Vec::begin() const +inline T & Vec::operator[](size_t index) { - return elements; + if (index > 0 && index < size()) + return *(elements + index); + else + cerr << "Index error:\nmax_index: " << size() - 1 + << " input index: " << index << endl; + exit(EXIT_FAILURE); +} +template +inline const T & Vec::operator[](size_t index) const +{ + if (index > 0 && index < size()) + return *(elements + index); + else + cerr << "Index error:\nmax_index: " << size() - 1 + << " input index: " << index << endl; + exit(EXIT_FAILURE); } template -inline T * Vec::end() const +inline void Vec::push_back(const T & t) { - return first_free; + chk_n_alloc(); + alloc.construct(first_free++, t); +} + +template +inline void Vec::push_back(T && t) +{ + chk_n_alloc(); + alloc.construct(first_free++, std::move(t)); } template @@ -198,27 +219,6 @@ void Vec::free() elements = first_free = cap = nullptr; } -template -inline T & Vec::operator[](size_t index) -{ - if (index > 0 && index < size()) - return *(elements + index); - else - cerr << "Index error:\nmax_index: " << size() - 1 - << " input index: " << index << endl; - exit(EXIT_FAILURE); -} -template -inline const T & Vec::operator[](size_t index) const -{ - if (index > 0 && index < size()) - return *(elements + index); - else - cerr << "Index error:\nmax_index: " << size() - 1 - << " input index: " << index << endl; - exit(EXIT_FAILURE); -} - template template inline void Vec::emplace_back(Args && ... args) @@ -227,6 +227,14 @@ inline void Vec::emplace_back(Args && ... args) alloc.construct(first_free++, std::forward(args)...); } +template +inline void Vec::swap(Vec & v) noexcept +{ + std::swap(elements, v.elements); + std::swap(first_free, v.first_free); + std::swap(cap, v.cap); +} + template inline pair Vec::alloc_n_copy(const T * const & st, const T * const & end) { @@ -254,14 +262,6 @@ void Vec::reallocate(size_t max) cap = newstart + newcapacity; } -template -inline void Vec::swap(Vec & v) noexcept -{ - std::swap(elements, v.elements); - std::swap(first_free, v.first_free); - std::swap(cap, v.cap); -} - template bool operator==(const Vec & v1, const Vec & v2) { @@ -299,8 +299,6 @@ bool operator>=(const Vec & v1, const Vec & v2) } - - int main() { // construc and move. From d4be28f2286d541907cc73168bbbb9ebb27f7d2e Mon Sep 17 00:00:00 2001 From: zhongquan Date: Thu, 21 Mar 2019 21:25:27 +0800 Subject: [PATCH 08/16] Add answer for exercise 16.61 --- ch16/README.md | 5 +++++ ch16/ex16_61_make_shared.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 ch16/ex16_61_make_shared.cpp diff --git a/ch16/README.md b/ch16/README.md index 86712418..03d854bd 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -532,3 +532,8 @@ vs.emplace_back(s); // 3: call copy constructor of std::string because the second parameter's type is lvalue reference(int &). ``` +# Exercise 16.61 + +> Define your own version of make_shared. + +[make_shared](ex16_60_make_shared.cpp) diff --git a/ch16/ex16_61_make_shared.cpp b/ch16/ex16_61_make_shared.cpp new file mode 100644 index 00000000..194e4877 --- /dev/null +++ b/ch16/ex16_61_make_shared.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +using std::shared_ptr; +using std::string; +using std::cout; +using std::endl; + +template +shared_ptr make_shared(Args && ... args) +{ + return shared_ptr(new T(std::forward(args)...)); +} + +struct Foo +{ + Foo(int n = 0) noexcept : bar(n) {cout << "Foo: constructor, bar = " << bar << endl;} + ~Foo() {cout << "Foo: destructor, bar = " << bar << endl;} + int getBar() const noexcept {return bar;} +private: + int bar; +}; + +int main() +{ + shared_ptr sp = make_shared(10); + cout << "The first Foo's bar is " << sp->getBar() << endl; + sp.reset(new Foo); + cout << "The second Foo's bar is " << sp->getBar() << endl; +} + From 228e9714c48a96b48fc92b6573b561c6c9123465 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Thu, 21 Mar 2019 21:26:45 +0800 Subject: [PATCH 09/16] Update README.md --- ch16/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch16/README.md b/ch16/README.md index 03d854bd..8d15d870 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -536,4 +536,4 @@ vs.emplace_back(s); > Define your own version of make_shared. -[make_shared](ex16_60_make_shared.cpp) +[make_shared](ex16_61_make_shared.cpp) From b8a10d8bbdaa13683d15687209eed3cd54179795 Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Fri, 22 Mar 2019 16:14:02 +0800 Subject: [PATCH 10/16] Update README.md --- ch16/README.md | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/ch16/README.md b/ch16/README.md index 8d15d870..2880b191 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -335,11 +335,12 @@ Then, the answers: > The library `max` function has two function parameters and returns the larger of its arguments. This function has one template type parameter. Could you call `max` passing it an int and a double? If so, how? If not, why not? -Yes. Specify the parameter explicitly: -> ```cpp -> int a = 6; double b = 6.1231; -> std::cout << std::max(a, b) << std::endl; -> ``` +> Yes. Specify the parameter explicitly: +```cpp +int a = 6; double b = 6.1231; +std::cout << std::max(a, b) << std::endl; +``` + > Normal conversions also apply for arguments whose template type parameter is explicitly specified. ## Exercise 16.38 @@ -394,10 +395,12 @@ More safer solution: <[Better `sum`](ex16_41_sum.cpp)> > (b) g(ci); > (c) g(i * ci); > ``` - -- (a) T: `int&` val: `int& &&` -> `int &` -- (b) T: `const int&` val: `const int& &&` -> `const int &` -- (c) T: `int` val: `int &&` + +```cpp +//T: `int&` val: `int& &&` -> `int &` +//T: `const int&` val: `const int& &&` -> `const int &` +//T: `int` val: `int &&` +``` > When we pass an lvalue `int` to a function parameter that is an rvalue reference to a template type parameter `T&&`, the compiler deduces the template type parameter as the argument’s lvalue reference type `int &`. @@ -443,17 +446,17 @@ Since C++11, [`std::allocator::construct`](http://en.cppreference.com/w/cpp/memo ## Exercise 16.49 > Explain what happens in each of the following calls: -```cpp -template void f(T); //1 -template void f(const T*); //2 -template void g(T); //3 -template void g(T*); //4 -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); -``` -> Answer: +>```cpp +>template void f(T); //1 +>template void f(const T*); //2 +>template void g(T); //3 +>template void g(T*); //4 +>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); +>``` + ```cpp g(42); // type: int(rvalue) call template 3 T: int instantiation: void g(int) g(p); // type: int * call template 4 T: int instantiation: void g(int *) @@ -475,6 +478,7 @@ f(p2); // type: const int * call template 2 T:int instantiation: vo ## Exercise 16.51 > Determine what sizeof...(Args) and sizeof...(rest) return for each call to foo in this section. + ```cpp template void foo(const T & t, const Args & ... rest); @@ -496,7 +500,7 @@ foo(i, s, s, d); // input in Args: string, string, double sizeof...(Args > What happens if we call print on a type that doesn’t have an << operator? -Error: +> Error: ```cpp std::vector v = {1, 2}; print(v); From 2765c029c2e6fcc11acb70f1cd1dbe273a3ea7aa Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Fri, 22 Mar 2019 16:16:12 +0800 Subject: [PATCH 11/16] Update README.md --- ch16/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ch16/README.md b/ch16/README.md index 2880b191..1c62091a 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -335,7 +335,7 @@ Then, the answers: > The library `max` function has two function parameters and returns the larger of its arguments. This function has one template type parameter. Could you call `max` passing it an int and a double? If so, how? If not, why not? -> Yes. Specify the parameter explicitly: +Yes. Specify the parameter explicitly: ```cpp int a = 6; double b = 6.1231; std::cout << std::max(a, b) << std::endl; @@ -397,9 +397,9 @@ More safer solution: <[Better `sum`](ex16_41_sum.cpp)> > ``` ```cpp -//T: `int&` val: `int& &&` -> `int &` -//T: `const int&` val: `const int& &&` -> `const int &` -//T: `int` val: `int &&` +//T: int& val: int& && -> int & +//T: const int& val: const int& && -> const int & +//T: int val: int && ``` > When we pass an lvalue `int` to a function parameter that is an rvalue reference to a template type parameter `T&&`, the compiler deduces the template type parameter as the argument’s lvalue reference type `int &`. @@ -500,7 +500,7 @@ foo(i, s, s, d); // input in Args: string, string, double sizeof...(Args > What happens if we call print on a type that doesn’t have an << operator? -> Error: +Error: ```cpp std::vector v = {1, 2}; print(v); From b2fd9e63a867d528de68997bcb6988fb4343beae Mon Sep 17 00:00:00 2001 From: zhongquan Date: Fri, 22 Mar 2019 19:19:42 +0800 Subject: [PATCH 12/16] Add answer for exercise 16.63,64,65,67 --- ch16/README.md | 41 +++++++++++++++--- ch16/ex16_58_emplace.cpp | 17 +++++--- ch16/ex16_63_count_template.cpp | 39 +++++++++++++++++ ch16/ex16_64_template_specialization.cpp | 54 ++++++++++++++++++++++++ ch16/ex16_65_debug_rep.cpp | 38 +++++++++++++++++ 5 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 ch16/ex16_63_count_template.cpp create mode 100644 ch16/ex16_64_template_specialization.cpp create mode 100644 ch16/ex16_65_debug_rep.cpp diff --git a/ch16/README.md b/ch16/README.md index 8d15d870..473a76c4 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -486,13 +486,13 @@ foo("hi"); // input in Args: None sizeof...(Args foo(i, s, s, d); // input in Args: string, string, double sizeof...(Args): 3 sizeof...(rest): 3 ``` -# Exercise 16.52 +## Exercise 16.52 > Write a program to check your answer to the previous question. [variadic template](ex16_52_variadic_template.cpp) -# Exercise 16.54 +## Exercise 16.54 > What happens if we call print on a type that doesn’t have an << operator? @@ -505,13 +505,13 @@ print(v); // return os << t << endl; ``` -# Exercise 16.58 +## Exercise 16.58 > Write the emplace_back function for your StrVec class and for the Vec class that you wrote for the exercises in 16.1.2 (p. 668). [emplace_back](ex16_58_emplace.cpp) -# Exercise 16.59 +## Exercise 16.59 > Assuming s is a string, explain svec.emplace_back(s). @@ -532,8 +532,39 @@ vs.emplace_back(s); // 3: call copy constructor of std::string because the second parameter's type is lvalue reference(int &). ``` -# Exercise 16.61 +## Exercise 16.61 > Define your own version of make_shared. [make_shared](ex16_61_make_shared.cpp) + +## Exercise 16.63 + +> Define a function template to count the number of occurrences of a given value in a vector. +Test your program by passing it a vector of doubles, a vector of ints, and a vector of strings. + +[count template](ex16_63_count_template.cpp) + +## Exercise 16.64 + +> Write a specialized version of the template from the previous exercise to handle vector and +a program that uses this specialization. + +[template specialization](ex16_64_template_specialization.cpp) + +## Exercise 16.65 + +> In § 16.3 (p. 698) we defined overloaded two versions of debug_rep one had a const char* +and the other a char* parameter. Rewrite these functions as specializations. + +[debug_rep specialization](ex16_65_debug_rep.cpp) + +## Exercise 16.67 + +> Would defining these specializations affect function matching for debug_rep? If so, how? If not, why not? + +No. It's just an instantiation of original function template. + +> Specializations instantiate a template; they do not overload it. As a result, +specializations do not affect function matching. + diff --git a/ch16/ex16_58_emplace.cpp b/ch16/ex16_58_emplace.cpp index 06f873dc..ca38124d 100644 --- a/ch16/ex16_58_emplace.cpp +++ b/ch16/ex16_58_emplace.cpp @@ -18,8 +18,10 @@ using std::string; using std::pair; using std::initializer_list; +// declaration for below templates . template class Vec; +// declaration of each template. template bool operator==(const Vec &, const Vec &); template bool operator!=(const Vec &, const Vec &); template bool operator< (const Vec &, const Vec &); @@ -31,12 +33,13 @@ template bool operator>=(const Vec &, const Vec &); template class Vec { - friend bool operator==(const Vec &, const Vec &); - friend bool operator!=(const Vec &, const Vec &); - friend bool operator< (const Vec &, const Vec &); - friend bool operator> (const Vec &, const Vec &); - friend bool operator<=(const Vec &, const Vec &); - friend bool operator>=(const Vec &, const Vec &); + // bound template friend. + friend bool operator==(const Vec &, const Vec &); + friend bool operator!=(const Vec &, const Vec &); + friend bool operator< (const Vec &, const Vec &); + friend bool operator> (const Vec &, const Vec &); + friend bool operator<=(const Vec &, const Vec &); + friend bool operator>=(const Vec &, const Vec &); public: Vec() : elements(nullptr), first_free(nullptr), cap(nullptr) {} @@ -54,7 +57,7 @@ class Vec T & operator[](size_t); const T & operator[](size_t) const; void push_back(const T &); - void push_back(T &&); + void push_back(T &&); // used for rvalue void reserve(size_t); void resize(size_t, const T & val = T()); void free(); diff --git a/ch16/ex16_63_count_template.cpp b/ch16/ex16_63_count_template.cpp new file mode 100644 index 00000000..f25661a7 --- /dev/null +++ b/ch16/ex16_63_count_template.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +using std::vector; +using std::string; +using std::cout; +using std::endl; + + +template +size_t count(const vector & v, T val) +{ + size_t c = 0; + for (auto & elem : v) + { + if (elem == val) + ++c; + } + return c; +} + + +int main() +{ + vector dv = {1, 2, 3, 4, 1, 3, 1, 2, 3, 4, 2, 4}; + vector iv = {2, 2, 1, 4, 2, 1, 4, 5, 6, 4, 3, 4}; + vector sv = {"hello", "bye", "good", "hello", "fun", "hello"}; + + cout << "{1, 2, 3, 4, 1, 3, 1, 2, 3, 4, 2, 4} has: "; + cout << count(dv, 1.0) << " 1" << endl; + + cout << "{2, 2, 1, 4, 2, 1, 4, 5, 6, 4, 3, 4} has: "; + cout << count(iv, 2) << " 2" << endl; + + cout << "{\"hello\", \"bye\", \"good\", \"hello\", \"fun\", \"hello\"} has: "; + cout << count(sv, string("hello")) << " hello" << endl; + +} + diff --git a/ch16/ex16_64_template_specialization.cpp b/ch16/ex16_64_template_specialization.cpp new file mode 100644 index 00000000..b1958ca3 --- /dev/null +++ b/ch16/ex16_64_template_specialization.cpp @@ -0,0 +1,54 @@ +#include +#include +#include +#include +using std::vector; +using std::string; +using std::cout; +using std::endl; + + +template +size_t count(const vector & v, T val) // if the second parameter is (const T &) +{ // a literal char string will be deduced as const char[N] + size_t c = 0; + for (auto & elem : v) + { + if (elem == val) + ++c; + } + return c; +} + +template <> +size_t count(const vector & v, const char * val) +{ + size_t c = 0; + for (auto p : v) + { + if (!std::strcmp(p, val)) + ++c; + } + return c; +} + +int main() +{ + vector dv = {1, 2, 3, 4, 1, 3, 1, 2, 3, 4, 2, 4}; + vector iv = {2, 2, 1, 4, 2, 1, 4, 5, 6, 4, 3, 4}; + vector sv = {"hello", "bye", "good", "hello", "fun", "hello"}; + + cout << "{1, 2, 3, 4, 1, 3, 1, 2, 3, 4, 2, 4} has: "; + cout << count(dv, 1.0) << " 1" << endl; + + cout << "{2, 2, 1, 4, 2, 1, 4, 5, 6, 4, 3, 4} has: "; + cout << count(iv, 2) << " 2" << endl; + + cout << "{\"hello\", \"bye\", \"good\", \"hello\", \"fun\", \"hello\"} has: "; + cout << count(sv, string("hello")) << " hello" << endl; + + vector cv = {"hello", "bye", "good", "hello", "fun", "hello"}; + cout << "{\"hello\", \"bye\", \"good\", \"hello\", \"fun\", \"hello\"} has: "; + cout << count(sv, string("hello")) << " hello" << endl; +} + diff --git a/ch16/ex16_65_debug_rep.cpp b/ch16/ex16_65_debug_rep.cpp new file mode 100644 index 00000000..a9fbe04a --- /dev/null +++ b/ch16/ex16_65_debug_rep.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +using std::string; +using std::ostringstream; +using std::cout; +using std::endl; + + +template +string debug_rep(T t) +{ + ostringstream ret; + ret << t; + return ret.str(); +} + +template <> +string debug_rep(const char * t) +{ + return t; +} + +template <> +string debug_rep(char * t) +{ + return t; +} + + +int main() +{ + string s = "this is a string"; + cout << debug_rep("this is a literal string") << endl; + cout << debug_rep(s) << endl; + cout << debug_rep('c') << endl; +} From 3c9bb5302d14e4defa94ef3c9d803acc6febdc04 Mon Sep 17 00:00:00 2001 From: zhongquan Date: Fri, 22 Mar 2019 19:26:00 +0800 Subject: [PATCH 13/16] update README.md --- ch16/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch16/README.md b/ch16/README.md index da2ea8f7..f349e837 100644 --- a/ch16/README.md +++ b/ch16/README.md @@ -567,7 +567,7 @@ and the other a char* parameter. Rewrite these functions as specializations. > Would defining these specializations affect function matching for debug_rep? If so, how? If not, why not? -No. It's just an instantiation of original function template. +No. It's just an instantiation of the original function template. > Specializations instantiate a template; they do not overload it. As a result, specializations do not affect function matching. From 4f1789c7ac31d16bfbbd637f3d41b1b200b750ee Mon Sep 17 00:00:00 2001 From: BAKEZQ Date: Sat, 23 Mar 2019 09:42:28 +0800 Subject: [PATCH 14/16] Add question information in REDAME.md --- ch17/README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/ch17/README.md b/ch17/README.md index fbea6d8d..545ac55b 100644 --- a/ch17/README.md +++ b/ch17/README.md @@ -108,4 +108,53 @@ Because `std::accumulate`'s third parameter is the initial value of the sum. It' > What would happen if your regex object in the previous program were initialized with "[^c]ei"? Test your program using that pattern to see whether your expectations were correct. -`[^c]ei` says we want any such letter that is followed by the letters 'ei', This pattern describes strings containing exactly **three** characters. The test words in [ex17_15](ex17_15.cpp) will all fail. \ No newline at end of file +`[^c]ei` says we want any such letter that is followed by the letters 'ei', This pattern describes strings containing exactly **three** characters. The test words in [ex17_15](ex17_15.cpp) will all fail. + +## Exercise 17.17 + +> Update your program so that it finds all the words in an input sequence that violiate the “ei” grammar rule. + +[regex](ex17.17.18/main.cpp) + +## Exercise 17.19 + +> Why is it okay to call m[4].str() without first checking whether m[4] was matched? + +> str() returns a string containing the matched poertion of the input.If not matched returns the empty string whcih can also be used for comparison. + +## Exercise 17.20 + +> Write your own version of the program to validate phone numbers. + +[validate phone numbers](ex17.19.20/main.cpp) + +## Exercise 12.21 + +> Rewrite your phone number program from § 8.3.2 (p. 323) to use the valid function defined in this section. + +[validate phone numbers](ex17.21/main.cpp) + +## Exercise 12.22 + +> Rewrite your phone program so that it allows any number of whitespace characters to separate the three parts of a phone number. + +[validate phone numbers](ex17.22/ex17.22/main.cpp) + +## Exercise 12.28 + +> Write a function that generates and returns a uniformly distributed random unsigned int each time it is called. + +[uniformly distribution](ex17.28.29.30/main.cpp) + +## Exercise 12.29 + +> Allow the user to supply a seed as an optional argument to the function you wrote in the previous exercise. + +[uniformly distribution](ex17.28.29.30/main.cpp) + +## Exercise 12.30 + +> Revise your function again this time to take a minimum and maximum value for the numbers that the function should return. + +[uniformly distribution](ex17.28.29.30/main.cpp) + From 02f978e1451758bfc2010cc9fd84bd0770607439 Mon Sep 17 00:00:00 2001 From: zhongquan Date: Sat, 23 Mar 2019 09:58:30 +0800 Subject: [PATCH 15/16] update README.md --- ch17/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ch17/README.md b/ch17/README.md index 545ac55b..b00b6450 100644 --- a/ch17/README.md +++ b/ch17/README.md @@ -128,31 +128,31 @@ Because `std::accumulate`'s third parameter is the initial value of the sum. It' [validate phone numbers](ex17.19.20/main.cpp) -## Exercise 12.21 +## Exercise 17.21 > Rewrite your phone number program from § 8.3.2 (p. 323) to use the valid function defined in this section. [validate phone numbers](ex17.21/main.cpp) -## Exercise 12.22 +## Exercise 17.22 > Rewrite your phone program so that it allows any number of whitespace characters to separate the three parts of a phone number. [validate phone numbers](ex17.22/ex17.22/main.cpp) -## Exercise 12.28 +## Exercise 17.28 > Write a function that generates and returns a uniformly distributed random unsigned int each time it is called. [uniformly distribution](ex17.28.29.30/main.cpp) -## Exercise 12.29 +## Exercise 17.29 > Allow the user to supply a seed as an optional argument to the function you wrote in the previous exercise. [uniformly distribution](ex17.28.29.30/main.cpp) -## Exercise 12.30 +## Exercise 17.30 > Revise your function again this time to take a minimum and maximum value for the numbers that the function should return. From 9c2cea9e0929194179abae23d35dc8a2ae521985 Mon Sep 17 00:00:00 2001 From: zhongquan Date: Sat, 23 Mar 2019 10:01:51 +0800 Subject: [PATCH 16/16] change ex17_22,33 file name --- ch17/README.md | 8 +++++++- ch17/ex17.22/{ex17.22 => }/main.cpp | 0 ch17/{ex_33.cpp => ex17_33_word_transformation.cpp} | 0 3 files changed, 7 insertions(+), 1 deletion(-) rename ch17/ex17.22/{ex17.22 => }/main.cpp (100%) rename ch17/{ex_33.cpp => ex17_33_word_transformation.cpp} (100%) diff --git a/ch17/README.md b/ch17/README.md index b00b6450..bbd1d05f 100644 --- a/ch17/README.md +++ b/ch17/README.md @@ -138,7 +138,7 @@ Because `std::accumulate`'s third parameter is the initial value of the sum. It' > Rewrite your phone program so that it allows any number of whitespace characters to separate the three parts of a phone number. -[validate phone numbers](ex17.22/ex17.22/main.cpp) +[validate phone numbers](ex17.22/main.cpp) ## Exercise 17.28 @@ -158,3 +158,9 @@ Because `std::accumulate`'s third parameter is the initial value of the sum. It' [uniformly distribution](ex17.28.29.30/main.cpp) +## Exercise 17.33 + +> Write a version of the word transformation program from §11.3.6 (p. 440) that allows multiple transformations +for a given word andrandomly selects which transformation to apply. + +[word transformation](ex17_33_word_transformation.cpp) diff --git a/ch17/ex17.22/ex17.22/main.cpp b/ch17/ex17.22/main.cpp similarity index 100% rename from ch17/ex17.22/ex17.22/main.cpp rename to ch17/ex17.22/main.cpp diff --git a/ch17/ex_33.cpp b/ch17/ex17_33_word_transformation.cpp similarity index 100% rename from ch17/ex_33.cpp rename to ch17/ex17_33_word_transformation.cpp