├── .gitattributes ├── 9781484249222.jpg ├── Chapter 1 ├── 01 - complex.cpp ├── 02 - ratio.cpp ├── 03 - random - Dice Roll.cpp ├── 04 - random - Dice Roll - bind.cpp ├── 05 - random - Seeding.cpp ├── 06 - random - Piecewise Constant Distribution.cpp ├── 07 - random - Piecewise Linear Distribution.cpp ├── 08 - valarray.cpp ├── 09 - valarray - slice.cpp ├── 10 - valarray - gslice.cpp ├── 11 - valarray - mask_array.cpp └── 12 - valarray - indirect_array.cpp ├── Chapter 2 ├── 01 - Moving.cpp ├── 02 - Move Assignment.cpp ├── 03 - Forwarding.cpp ├── 04 - pair.cpp ├── 05 - tuple.cpp ├── 06 - tuple - apply.cpp ├── 07 - byte.cpp ├── 08 - rel_ops.cpp ├── 09 - unique_ptr.cpp ├── 10 - unique_ptr - Array.cpp ├── 11 - unique_ptr - Take Ownership.cpp ├── 12 - unique_ptr - fopen.cpp ├── 13 - shared_ptr.cpp ├── 14 - shared_ptr - fopen.cpp ├── 15 - shared_ptr - Casts.cpp ├── 16 - shared_ptr - Aliasing.cpp ├── 17 - weak_ptr.cpp ├── 18 - enable_shared_from_this.cpp ├── 19 - my_plus.cpp ├── 20 - reference_wrapper.cpp ├── 21 - sort.cpp ├── 22 - plus.cpp ├── 23 - bind.cpp ├── 24 - function.cpp ├── 25 - Functors for Class Members.cpp ├── 26 - mem_fn.cpp ├── 27 - initializer_list.cpp ├── 28 - initializer_list - ExampleClass.cpp ├── 29 - optional.cpp ├── 30 - optional - nullopt.cpp ├── 31 - optional - in-place.cpp ├── 32 - variant - default construction.cpp ├── 33 - variant - in-place.cpp ├── 34 - variant - example.cpp ├── 35 - variant - visitation.cpp ├── 36 - any.cpp ├── 37 - duration.cpp ├── 38 - time_point.cpp ├── 39 - clock.cpp ├── 40 - strftime.cpp ├── 41 - typeid.cpp ├── 42 - integral_constant.cpp ├── 43 - Type Traits.cpp ├── 44 - my_decay.cpp ├── 45 - copy.cpp ├── 46 - copy - constexpr if.cpp ├── 47 - void_t.cpp ├── 48 - declval.cpp └── 49 - invoke.cpp ├── Chapter 3 ├── 01 - non-member begin and end.cpp ├── 02 - range-based for loop.cpp ├── 03 - vector.cpp ├── 04 - deque.cpp ├── 05 - array.cpp ├── 06 - list.cpp ├── 07 - size.cpp ├── 08 - bitset.cpp ├── 09 - Container Adapters.cpp ├── 10 - map.cpp ├── 11 - multimap.cpp ├── 12 - set.cpp ├── 13 - moving nodes.cpp ├── 14 - merging.cpp ├── 15 - hash - Person.cpp ├── 16 - allocators.cpp └── 17 - memory resources.cpp ├── Chapter 4 ├── 01 - transform.cpp ├── 02 - all_of.cpp ├── 03 - find_if.cpp ├── 04 - lower_bound.cpp ├── 05 - equal_range.cpp ├── 06 - searching.cpp ├── 07 - generate and iota.cpp ├── 08 - copy_if.cpp ├── 09 - unique.cpp ├── 10 - rotate.cpp ├── 11 - partial_sort_copy.cpp ├── 12 - nth_element.cpp ├── 13 - shuffle.cpp ├── 14 - reduce.cpp ├── 15 - inner_product.cpp ├── 16 - parallel sort.cpp └── 17 - Iterator Adaptors.cpp ├── Chapter 5 ├── 01 - Manipulators.cpp ├── 02 - Error Handling.cpp ├── 03 - ostream.cpp ├── 04 - istream.cpp ├── 05 - sstream.cpp ├── 06 - fstream - input and output.cpp ├── 07 - fstream.cpp ├── 08 - Custom Output and Extraction Operator.cpp ├── 09 - Custom Manipulators.cpp ├── 10 - ostream_iterator.cpp ├── 11 - istream_iterator.cpp ├── 12 - Stream Iterators.cpp ├── 13 - Stream Buffers - Redirect.cpp ├── 14 - Stream Buffers - Read File.cpp ├── 15 - filesystem - decomposition.cpp ├── 16 - filesystem - filename.cpp ├── 17 - filesystem - composition.cpp ├── 18 - filesystem - directory listing.cpp ├── 19 - printf.cpp ├── 20 - printf - Formatting.cpp └── 21 - scanf.cpp ├── Chapter 6 ├── 01 - string.cpp ├── 02 - string_view.cpp ├── 03 - codecvt.cpp ├── 04 - Global Locale.cpp ├── 05 - use_facet.cpp ├── 06 - Monetary Formatting.cpp ├── 07 - String Ordering.cpp ├── 08 - Combining Facets.cpp ├── 09 - Custom Facets - yes_no.cpp ├── 10 - Custom Facets - Accounting.cpp ├── 11 - C Locales.cpp ├── 12 - regex.cpp ├── 13 - Tokenizing.cpp └── 14 - regex_replace.cpp ├── Chapter 7 ├── 01 - Threads.cpp ├── 02 - Joining.cpp ├── 03 - Futures.cpp ├── 04 - Mutual Exclusion.cpp ├── 05 - shared_lock.cpp ├── 06 - call_once.cpp ├── 07 - Condition Variables.cpp ├── 08 - Cache-line Size.cpp ├── 09 - Atomic Operations.cpp ├── 10 - Lock-free.cpp └── 11 - Atomic Person.cpp ├── Chapter 8 ├── 01 - assert.cpp ├── 02 - Exception Pointers.cpp ├── 03 - Nested Exceptions.cpp ├── 04 - system_error.cpp ├── 05 - cerrno.cpp └── 06 - uncaught_exceptions.cpp ├── Common └── Person.h ├── Contributing.md ├── LICENSE.txt ├── README.md └── errata.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /9781484249222.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/cpp17-standard-library-quick-ref/cd62302142a290a438178541c8646f39d3054143/9781484249222.jpg -------------------------------------------------------------------------------- /Chapter 1/01 - complex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::complex c(1, 2); // Both arguments are optional (default: 0) 7 | std::cout << "c=" << c.real() << '+' << c.imag() << 'i' << '\n'; // c=1+2i 8 | c.real(3); c.imag(3); c += 1; 9 | std::cout << "norm(" << c << ") = " << std::norm(c); // norm((4,3)) = 25 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 1/02 - ratio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using a_third = std::ratio<1, 3>; 8 | using a_half = std::ratio<1, 2>; 9 | using two_quart = std::ratio<2, 4>; 10 | using sum = std::ratio_add; 11 | 12 | std::cout << two_quart::num << '/' << two_quart::den << '\n'; // 1/2 13 | std::cout << sum::num << '/' << sum::den << '\n'; // 5/6 14 | std::cout << std::boolalpha; /* print true/false instead of 1/0 */ 15 | std::cout << (typeid(two_quart) == typeid(a_half)) << '\n'; // false 16 | std::cout << (typeid(two_quart::type) == typeid(a_half)) << '\n'; // true 17 | std::cout << std::ratio_equal::value << '\n'; // true 18 | 19 | std::cout << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 1/03 - random - Dice Roll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::default_random_engine generator; 7 | std::uniform_int_distribution distribution(1, 6); 8 | int dice_roll = distribution(generator); // 1 <= dice_roll <= 6 9 | std::cout << dice_roll << std::endl; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter 1/04 - random - Dice Roll - bind.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::default_random_engine generator; 8 | std::uniform_int_distribution distribution(1, 6); 9 | std::function roller = std::bind(distribution, generator); 10 | for (int i = 0; i < 100; ++i) 11 | { 12 | std::cout << roller() << '\n'; 13 | } 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 1/05 - random - Seeding.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::random_device seeder; 8 | const auto seed = seeder.entropy() ? seeder() : std::time(nullptr); 9 | std::default_random_engine generator( 10 | static_cast(seed)); 11 | 12 | std::uniform_int_distribution distribution(1, 6); 13 | int dice_roll = distribution(generator); // 1 <= dice_roll <= 6 14 | std::cout << dice_roll << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 1/06 - random - Piecewise Constant Distribution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::mt19937 generator; // Default-seeded for this example 8 | std::vector intervals = { 1,20,40,60,80 }; 9 | std::vector weights = { 1,3,1,3 }; 10 | std::piecewise_constant_distribution distribution( 11 | begin(intervals), end(intervals), begin(weights)); 12 | int value = static_cast(distribution(generator)); 13 | std::cout << value << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 1/07 - random - Piecewise Linear Distribution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::mt19937 generator; // Default-seeded for this example 8 | std::vector intervals = { 1,20,40,60,80 }; 9 | std::vector weights = { 1,3,1,3,1 }; 10 | std::piecewise_linear_distribution distribution( 11 | begin(intervals), end(intervals), begin(weights)); 12 | int value = static_cast(distribution(generator)); 13 | std::cout << value << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 1/08 - valarray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::valarray ints1(7); // 7 zero-initialized integers 7 | std::valarray doubles = { 1.1, 2.2, 3.3 }; // Deduces std::valarray 8 | int carray[] = { 6,5,4,3,2,1 }; 9 | std::valarray ints2(carray, 3); // Contains 6,5,4 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 1/09 - valarray - slice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::valarray ints = { 0,1,2,3,4,5,6,7 }; 7 | std::slice mySlicer(2, 3, 2); 8 | const std::valarray& constInts = ints; 9 | auto copies = constInts[mySlicer]; // valarray with copies of 2,4,6 10 | auto refs = ints[mySlicer]; // slice_array with references to 2,4,6 11 | std::valarray factors{ 6,3,2 }; 12 | refs *= factors; // ints will be 0,1,12,3,12,5,12,7 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 1/10 - valarray - gslice.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::valarray a = { 0,11,22,33,44,55,66,77,88,99,111 }; 7 | std::valarray sizes{ 2,3 }; // required here, otherwise it 8 | // deduces to std::valarray. 9 | std::valarray strides{ 5,2 }; 10 | std::valarray r = a[std::gslice(1, sizes, strides)]; //11,33,55,66,88,111 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 1/11 - valarray - mask_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::valarray ints = { 0,1,2,3,4,5,6,7,8,9,10 }; 7 | // Construct a valarray with true for all even elements in ints. 8 | std::valarray even = ((ints % 2) == 0); 9 | // Count the number of true values in even. (see Chapter 4) 10 | auto count = std::count(begin(even), end(even), true); 11 | // Construct a valarray with count elements of value 4. 12 | std::valarray factors(4, count); 13 | // Multiply the even elements in ints with a factor of 4. 14 | ints[even] *= factors; // 0,1,8,3,16,5,24,7,32,9,40 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 1/12 - valarray - indirect_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::valarray ints = { 0,1,2,3,4 }; 7 | std::valarray indices = { 1,3,4 }; // required here. 8 | ints[indices] = -1; // 0,-1,2,-1,-1 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 2/01 - Moving.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void f(std::string s) 5 | { 6 | std::cout << "Moved or copied: " << s << '\n'; 7 | } 8 | 9 | void g(std::string&& s) 10 | { 11 | std::cout << "Moved " << s << '\n'; 12 | } 13 | 14 | std::string h() 15 | { 16 | std::string s("test"); 17 | return s; // moved implicitly, = std::move(s) 18 | } 19 | 20 | int main() 21 | { 22 | std::string test("123"); 23 | f(test); // test copied to a new string 24 | f(std::move(test)); // test moved to a new string (move constructor) 25 | // std::cout << test; --> Undefined: may give "", "123", or simply crash 26 | test = "456"; // test is reinitialized, and may be used again 27 | // g(test); --> Does not compile 28 | g(std::move(test)); 29 | g(std::string("789")); // Unnamed objects are moved implicitly 30 | g(h()); 31 | 32 | std::cout << std::endl; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter 2/02 - Move Assignment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::string one("Test 123"); 7 | std::string other; 8 | other = std::move(one); 9 | // std::cout << one; --> Undefined behavior: one was moved to other 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 2/03 - Forwarding.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A 4 | { 5 | A() {}; 6 | A(const A&) = delete; // A objects cannot be copied 7 | }; 8 | 9 | void f(const A&) 10 | { 11 | std::cout << "lval, "; // forwarded as lvalue reference 12 | } 13 | 14 | void f(A&&) 15 | { 16 | std::cout << "rval, "; // forwarded as rvalue reference 17 | } 18 | 19 | // Three different forwarding (fwd) schemes: 20 | template void good_fwd(T&& t) { f(std::forward(t)); } 21 | template void bad_fwd(T&& t) { f(t); } 22 | template void ugly_fwd(T t) { f(t); } 23 | 24 | int main() 25 | { 26 | A a; 27 | good_fwd(a); good_fwd(std::move(a)); good_fwd(A()); // lval, rval, rval, 28 | bad_fwd(a); bad_fwd(std::move(a)); bad_fwd(A()); // lval, lval, lval, 29 | // ugly_fwd(a); ugly_fwd(std::move(a)); ugly_fwd(A()); --> error: 3x copy 30 | 31 | std::cout << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 2/04 - pair.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../Common/Person.h" 5 | 6 | int main() 7 | { 8 | // Basic constructor 9 | std::pair p1(42u, Person("Douglas", "Adams")); 10 | 11 | // Using C++17 class template argument deduction (CTAD) 12 | std::pair p2(42u, Person("Douglas", "Adams")); 13 | 14 | // Construction using std::make_pair() 15 | auto p3 = std::make_pair(42u, Person("Douglas", "Adams")); 16 | 17 | // Piecewise construction 18 | std::pair p4(std::piecewise_construct, 19 | std::make_tuple(42u), std::forward_as_tuple("Douglas", "Adams")); 20 | 21 | // Deconstructing a pair with C++17 structured bindings 22 | auto [number, person] = p1; 23 | 24 | std::cout << std::endl; 25 | } 26 | -------------------------------------------------------------------------------- /Chapter 2/05 - tuple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::tuple t(1, 2, 0.3, std::string("4")); // Using C++17 CTAD 8 | // auto t = std::make_tuple(1, 2, 0.3, std::string("4")); // Using make_tuple() 9 | std::cout << std::get<0>(t) << '\n'; // get using 0-based index 10 | std::get<2>(t) = 3.0; // no set required: get returns a reference 11 | std::cout << std::get(t) << '\n'; // get using unique type 12 | // std::cout << std::get(t) << '\n'; --> ambiguous: compiler error! 13 | std::string s1 = std::get<3>(std::move(t)); // move a value out of a tuple 14 | 15 | 16 | { 17 | // Deconstructing a tuple using C++17 structured bindings 18 | auto [one, two, three, s2] = t; // = std::move(t) moves string into s 19 | } 20 | 21 | { 22 | // Deconstructing a tuple using std::tie() 23 | int one, two; 24 | std::string s2; 25 | std::tie(one, two, std::ignore, s2) = t; // = std::move(t) moves to s 26 | } 27 | 28 | { 29 | std::cout << std::tuple_size::value << '\n'; // 4 30 | std::tuple_element<0, decltype(t)>::type one = std::get<0>(t); // int 31 | std::cout << one << std::endl; 32 | } 33 | 34 | std::cout << std::endl; 35 | } 36 | -------------------------------------------------------------------------------- /Chapter 2/06 - tuple - apply.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void f(const std::string& s, int i) 6 | { 7 | std::cout << "f() called with: " << s << " and " << i << std::endl; 8 | } 9 | 10 | int main() 11 | { 12 | std::tuple tuple("test", 123); 13 | std::apply(f, tuple); 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 2/07 - byte.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::byte b1{ 1 }, b2{ 42 }; // More realistic examples would read bytes 7 | std::byte b = b1 | b2; // from a file (Chapter 5), the network, ... 8 | b <<= 5; 9 | int v1 = static_cast(b); 10 | auto v2 = unsigned(b); 11 | long v3 = std::to_integer(b); 12 | std::cout << v1 << ' ' << v2 << ' ' << v3 << std::endl; // 96 96 96 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 2/08 - rel_ops.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | int main() 6 | { 7 | // Works even though only operator< is defined for our Person class: 8 | using namespace std::rel_ops; 9 | const bool comparison = (Person("Alexander") > Person("Bob")); 10 | std::cout << comparison; // 0 (Alexander is not greater) 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 2/09 - unique_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | void DoSomethingWith(Person& person) 6 | { 7 | /* ... */ 8 | } 9 | 10 | int main() 11 | { 12 | { 13 | std::unique_ptr jeff(new Person("Jeffrey")); 14 | if (jeff != nullptr) 15 | jeff->SetLastName("Griffin"); 16 | if (jeff) 17 | DoSomethingWith(*jeff); // Dereference as Person& 18 | } // jeff is deleted, even if DoSomethingWith() throws 19 | 20 | 21 | { 22 | auto jeff = std::make_unique("Jeffrey"); 23 | if (jeff != nullptr) 24 | jeff->SetLastName("Griffin"); 25 | if (jeff) 26 | DoSomethingWith(*jeff); // Dereference as Person& 27 | } // jeff is deleted, even if DoSomethingWith() throws 28 | 29 | 30 | std::cout << std::endl; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter 2/10 - unique_ptr - Array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void DoSomethingWith(int* data) 5 | { 6 | /* ... */ 7 | } 8 | 9 | int main() 10 | { 11 | { 12 | std::unique_ptr array(new int[123]); // or make_unique(123) 13 | for (int i = 0; i < 123; ++i) 14 | array[i] = i; 15 | DoSomethingWith(array.get()); // Pass raw int* pointer 16 | } // array is delete[]'d, even if DoSomethingWith() throws 17 | 18 | 19 | { 20 | auto a2 = std::make_unique(123); // 123 times zero 21 | std::unique_ptr a1(new int[123]); // uninitialized values 22 | } 23 | 24 | 25 | std::cout << std::endl; 26 | } 27 | -------------------------------------------------------------------------------- /Chapter 2/11 - unique_ptr - Take Ownership.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | void TakeOwnership(Person* person) 6 | { 7 | /* Do something with person and delete it! */ 8 | } 9 | 10 | int main() 11 | { 12 | auto niles = std::make_unique("Niles", "Crane"); 13 | niles.reset(new Person("Niles", "Butler")); // Niles Crane is deleted 14 | TakeOwnership(niles.release());// TakeOwnership() must delete Niles Butler 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 2/12 - unique_ptr - fopen.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void DoSomethingWith(FILE* file) 9 | { 10 | /* ... */ 11 | } 12 | 13 | int main() 14 | { 15 | { 16 | std::unique_ptr> smartFilePtr(fopen("test.txt", "r"), fclose); 17 | DoSomethingWith(smartFilePtr.get()); 18 | } // The FILE* is closed, even if DoSomethingWith() throws 19 | 20 | std::cout << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter 2/13 - shared_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | int main() 6 | { 7 | { 8 | auto bond = std::make_shared(007); // bond.use_count() == 1 9 | auto james = bond; // james.use_count() == 2 && bond.use_count() == 2 10 | bond.reset(); // james.use_count() == 1 && bond.use_count() == 0 11 | } // 007 is deleted 12 | 13 | 14 | { 15 | auto muhammed = std::make_unique("Muhammed"); 16 | std::shared_ptr mountain = std::move(muhammed); 17 | //muhammed = std::move(mountain); // mountain cannot be moved to Muhammed 18 | } 19 | 20 | std::cout << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter 2/14 - shared_ptr - fopen.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS 1 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void DoSomethingWith(FILE* file) 8 | { 9 | /* ... */ 10 | } 11 | 12 | int main() 13 | { 14 | { 15 | std::shared_ptr smartFilePtr(fopen("test.txt", "r"), fclose); 16 | DoSomethingWith(smartFilePtr.get()); 17 | } // The FILE* is closed, even if DoSomethingWith() throws 18 | 19 | std::cout << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 2/15 - shared_ptr - Casts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { public: virtual ~A() {}; }; 5 | class B : public A {}; 6 | class C {}; 7 | 8 | int main() 9 | { 10 | std::shared_ptr a = std::make_shared(); // a points to a new B() 11 | std::shared_ptr b = std::dynamic_pointer_cast(a); 12 | std::shared_ptr c = std::dynamic_pointer_cast(a); 13 | // (c == nullptr) && (a.use_count() == b.use_count() == 2) 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 2/16 - shared_ptr - Aliasing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct A 5 | { 6 | int* member; 7 | /* ... */ 8 | }; 9 | 10 | int main() 11 | { 12 | auto a = std::make_shared(); 13 | auto m = std::shared_ptr(a, a->member); // aliasing constructor 14 | // a.use_count() == m.use_count() == 2 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 2/17 - weak_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void DoSomethingWith(std::string& s) 5 | { 6 | /* ... */ 7 | } 8 | 9 | int main() 10 | { 11 | auto s = std::make_shared("SharedString"); 12 | auto w = std::weak_ptr(s); //w.use_count() == s.use_count() == 1 13 | { 14 | std::shared_ptr s2 = w.lock(); 15 | DoSomethingWith(*s2); // w.use_count() == s.use_count() == 2 16 | } // w.use_count() == s.use_count() == 1 17 | s.reset(); // w.expired() == true 18 | 19 | 20 | std::cout << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter 2/18 - enable_shared_from_this.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class MyObject : public std::enable_shared_from_this 5 | { 6 | public: 7 | std::shared_ptr pointer() 8 | { 9 | return shared_from_this(); 10 | } 11 | }; 12 | 13 | 14 | int main() 15 | { 16 | auto p1 = std::make_shared(); 17 | auto p2 = p1->pointer(); 18 | auto p3 = p1->shared_from_this(); 19 | 20 | try 21 | { 22 | MyObject unshared; 23 | auto p4 = unshared.shared_from_this(); // Throws std::bad_weak_ptr 24 | } 25 | catch (const std::bad_weak_ptr&) 26 | { 27 | std::cout << "Caught std::bad_weak_ptr\n"; 28 | } 29 | 30 | 31 | std::cout << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 2/19 - my_plus.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct my_plus 5 | { 6 | T operator() (const T& x, const T& y) const { return x + y; } 7 | }; 8 | 9 | int main() 10 | { 11 | my_plus functor; 12 | std::cout << functor(11, 22) << std::endl; // 33 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/20 - reference_wrapper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int i = 234; 8 | std::vector v{ std::ref(i) }; // cf. Chapter 3 9 | // Or: std::vector> v{ std::ref(i) }; 10 | v[0].get() = 432; // Occasionally, like here, an explicit get() is needed 11 | // (v[0] returns reference_wrapper&, not int&). 12 | std::cout << v[0] << "==" << i << std::endl; // 432==432 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/21 - sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | int array[] = { 7, 9, 7, 2, 0, 4 }; 8 | std::sort(std::begin(array), std::end(array), std::greater()); 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 2/22 - plus.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::plus<> functor; // defaults to std::plus 7 | std::cout << functor(234, 432) << ' ' << functor(1.101, 2.0405) << std::endl; 8 | 9 | std::cout << std::endl; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter 2/23 - bind.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | bool my_less(int x, int y) { return x < y; } 8 | void f(std::string& x, char y) { x += y; } 9 | 10 | int main() 11 | { 12 | using namespace std::placeholders; // contains _1, _2, _3, ... 13 | auto my_greater = std::bind(my_less, _2, _1); // function + swap _1 _2 14 | auto twice = std::bind(std::plus{}, _1, _1);// functor + twice _1 15 | auto plus5 = std::bind(std::plus{}, _1, 5); // functor + fixed 5 16 | std::cout << my_greater(twice(13), plus5(20)) << '\n'; // 1 (true) 17 | 18 | // bind() expressions may be nested whilst sharing placeholders: 19 | auto g = std::bind(my_greater, std::bind(twice, _1), std::bind(plus5, _1)); 20 | std::cout << g(10) << ' ' << g(4) << '\n'; // 1 0 (true false) 21 | 22 | // Use std::ref()/cref() to pass references 23 | // (For containers, algorithms, and strings see chapters 3, 4, and 6) 24 | std::vector v{ 'c', 'o', 'n', 'c', 'a', 't' }; 25 | std::string concat; 26 | std::for_each(begin(v), end(v), std::bind(f, std::ref(concat), _1)); 27 | std::cout << concat << std::endl; 28 | 29 | std::cout << std::endl; 30 | } 31 | -------------------------------------------------------------------------------- /Chapter 2/24 - function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool my_less(int x, int y) { return x < y; } 5 | 6 | int main() 7 | { 8 | std::function test = my_less; // function 9 | test = &my_less; // function pointer 10 | test = std::less<>{}; // function object 11 | test = [](int x, int y) { return x < y; }; // lambda closure 12 | if (test) std::cout << test(234, 432) << std::endl; // 1 (true) 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/25 - Functors for Class Members.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct my_struct { int val; bool fun(int i) { return val == i; } }; 5 | 6 | int main() 7 | { 8 | my_struct s{ 234 }; 9 | 10 | std::function f_get_val = &my_struct::val; 11 | std::function f_call_fun = &my_struct::fun; 12 | std::cout << f_get_val(s) << ' ' << f_call_fun(s, 123) << std::endl; 13 | 14 | using std::placeholders::_1; 15 | auto b_get_val = std::bind(&my_struct::val, _1); 16 | auto b_call_fun_on_s = std::bind(&my_struct::fun, std::ref(s), _1); 17 | std::cout << b_get_val(s) << ' ' << b_call_fun_on_s(234) << std::endl; 18 | 19 | auto m_get_val = std::mem_fn(&my_struct::val); 20 | auto m_call_fun = std::mem_fn(&my_struct::fun); 21 | std::cout << m_get_val(s) << ' ' << m_call_fun(s, 456) << std::endl; 22 | 23 | 24 | std::cout << std::endl; 25 | } 26 | -------------------------------------------------------------------------------- /Chapter 2/26 - mem_fn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | std::vector v{ "Test", "", "123", "", "" }; 10 | std::cout << std::count_if(begin(v), end(v), std::mem_fn(&std::string::empty)); // 3 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 2/27 - initializer_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | auto list = { 1, 2, 3 }; // list has type std::initializer_list 7 | 8 | std::cout << std::endl; 9 | } 10 | -------------------------------------------------------------------------------- /Chapter 2/28 - initializer_list - ExampleClass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class ExampleClass { 5 | public: 6 | ExampleClass(int, int) { std::cout << "(int, int) ctor" << '\n'; } 7 | ExampleClass(std::initializer_list) { std::cout << "initializer_list ctor" << '\n'; } 8 | }; 9 | 10 | int main() 11 | { 12 | ExampleClass a(1, 2); // (int, int) constructor is used 13 | ExampleClass b{ 1, 2 }; // initializer_list constructor is used 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 2/29 - optional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::optional divide(double n, double d) 5 | { 6 | if (d != 0.0) return n / d; 7 | else return {}; 8 | } 9 | 10 | int main() 11 | { 12 | auto result = divide(12, 3); 13 | if (result.has_value()) 14 | std::cout << "result is: " << result.value(); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/30 - optional - nullopt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::optional divide(double n, double d) 5 | { 6 | if (d != 0.0) return n / d; 7 | else return std::nullopt; 8 | } 9 | 10 | int main() 11 | { 12 | auto result = divide(12, 3); 13 | if (result != std::nullopt) 14 | std::cout << "result is: " << result.value(); 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/31 - optional - in-place.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | auto opt = std::optional(std::in_place, "Hello"); 8 | } 9 | -------------------------------------------------------------------------------- /Chapter 2/32 - variant - default construction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class NoDefaultCtor { 5 | public: 6 | NoDefaultCtor() = delete; 7 | NoDefaultCtor(int) {} 8 | }; 9 | 10 | int main() 11 | { 12 | std::variant v; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 2/33 - variant - in-place.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::variant v(std::in_place_type, "Hello"); 8 | } 9 | -------------------------------------------------------------------------------- /Chapter 2/34 - variant - example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::variant v1; // Value-constructed variant contains 8 | // a value-initialized value of the 9 | // first alternative type (int). 10 | std::cout << std::holds_alternative(v1) << std::endl; // 1 (true) 11 | std::cout << v1.index() << std::endl; // 0 12 | 13 | v1 = "In manufacturing, we try to stamp out variance. " 14 | "With people, variance is everything."; 15 | 16 | std::cout << std::get<1>(v1) << std::endl; // In manu... 17 | std::cout << *std::get_if(&v1) << std::endl; // In manu... 18 | } 19 | -------------------------------------------------------------------------------- /Chapter 2/35 - variant - visitation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class MyVisitor { 6 | public: 7 | auto operator()(int, int) const { return "Two ints."; } 8 | auto operator()(const std::string&, const std::string&) const { 9 | return "Two strings."; 10 | } 11 | auto operator()(const std::string&, int) const { 12 | return "A string and an int."; 13 | } 14 | auto operator()(int, const std::string&) const { 15 | return "An int and a string."; 16 | } 17 | }; 18 | 19 | int main() 20 | { 21 | std::variant v1 = { "Hello world!" }, v2 = 42; 22 | 23 | // A simple visitor. 24 | auto myVisitor = [](auto && value) { std::cout << value << std::endl; }; 25 | std::visit(myVisitor, v1); // Hello world! 26 | std::visit(myVisitor, v2); // 42 27 | 28 | // A type-matching visitor to handle specific types. 29 | struct IsNullVisitor { 30 | bool operator()(const std::string& s) const { return s.empty(); } 31 | bool operator()(int i) const { return i == 0; } 32 | }; 33 | 34 | std::cout << std::visit(IsNullVisitor{}, v1) << std::endl; // 0 35 | std::cout << std::visit(IsNullVisitor{}, v2) << std::endl; // 0 36 | 37 | // An int and a string. 38 | std::cout << std::visit(MyVisitor{}, v1, v2) << std::endl; 39 | } 40 | -------------------------------------------------------------------------------- /Chapter 2/36 - any.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::any a; 7 | std::cout << a.has_value() << std::endl; // 0 8 | a = 42; 9 | std::cout << a.type().name() << std::endl; // int 10 | a = "Any sufficiently advanced technology is indistinguishable from magic"; 11 | std::cout << a.type().name() << std::endl; // const char* 12 | std::cout << std::any_cast(a) << std::endl; // Any suffi... 13 | a.reset(); 14 | std::cout << a.type().name() << std::endl; // void 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 2/37 - duration.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace std::chrono; 7 | using hours_t = duration>; 8 | using milli_t = duration; // milli==ratio<1,1000> 9 | const hours_t one_hour(1); 10 | const milli_t ms(one_hour); 11 | std::cout << "1h = " << ms.count() << "ms\n"; // 1h = 3600000ms 12 | 13 | 14 | // const hours_t back_to_hours(ms); <-- error (int64_t would be truncated) 15 | const auto back_to_hours = duration_cast(ms); 16 | 17 | 18 | const auto secs = duration_cast(0.5h); 19 | std::cout << "0.5h = " << secs.count() << "s\n"; // 0.5h = 1800s 20 | 21 | 22 | const auto result = duration_cast((12min + .5h) / 2 + (100ns >= 1ms ? -3h : ++59s)); 23 | std::cout << result.count(); 24 | 25 | 26 | auto s1 = -4.2s; // -4.2s 27 | auto s2 = std::chrono::floor(s1); // -5s 28 | auto s3 = std::chrono::abs(s1); // 4.2s 29 | 30 | 31 | std::cout << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 2/38 - time_point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using namespace std::chrono; 7 | 8 | time_point one_hour(1h); // 1h since epoch 9 | time_point sixty_minutes = one_hour; 10 | std::cout << (one_hour - sixty_minutes).count() << std::endl; // 0 11 | 12 | 13 | auto one_hour2 = time_point_cast(sixty_minutes); 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 2/39 - clock.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS // To make sure ctime() works with Visual C++. 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | using std::chrono::steady_clock; 10 | const steady_clock::time_point before = steady_clock::now(); 11 | std::cout << steady_clock::period::num << '/' /* Possible output: */ 12 | << steady_clock::period::den << '\n'; // 1/1000000000 13 | std::cout << (steady_clock::now() - before).count() << '\n'; // 34721 14 | 15 | 16 | using std::chrono::system_clock; 17 | const auto now = system_clock::now(); /* Possible output: */ 18 | const time_t now_time_t = system_clock::to_time_t(now); 19 | std::cout << now.time_since_epoch().count() << '\n'; // 1445470140000 20 | std::cout << ctime(&now_time_t) << '\n'; // Wed Oct 21 16:29:00 2015 21 | 22 | 23 | std::cout << std::endl; 24 | } 25 | -------------------------------------------------------------------------------- /Chapter 2/40 - strftime.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS // To make sure localtime() works with Visual C++. 2 | 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | time_t time = std::time(nullptr); 9 | tm time_tm = *std::localtime(&time); 10 | char buffer[256]; 11 | strftime(buffer, sizeof(buffer), "Today is %a %e/%m%n", &time_tm); 12 | std::cout << buffer; // Today is Sat 30/01 13 | strftime(buffer, sizeof(buffer), "%c--%x %X", &time_tm); 14 | std::cout << buffer << '\n'; // Sat Jan 30 17:58:23 2016--01/30/16 17:58:23 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 2/41 - typeid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | const std::string s = "Hello"; 7 | std::cout << typeid(s).name() << '\n'; 8 | std::cout << (typeid(typeid(s).name()) == typeid(s.data())); // 1 (true) 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 2/42 - integral_constant.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using answer_t = std::integral_constant; 7 | std::cout << answer_t::value << std::endl; // static 'value' member 8 | std::cout << answer_t{} << std::endl; // implicit casting operator 9 | std::cout << answer_t{}() << std::endl; // function call operator 10 | } 11 | -------------------------------------------------------------------------------- /Chapter 2/43 - Type Traits.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::cout << std::boolalpha; // Print true/false instead of 1/0 7 | std::cout << std::is_integral::value << '\n'; // true 8 | std::cout << std::is_integral_v << '\n'; // true 9 | std::cout << std::is_class_v> << '\n'; // true 10 | std::cout << std::is_function_v << '\n'; // true 11 | std::cout << std::is_function_v << '\n'; // true 12 | std::cout << std::is_pointer_v << '\n'; // true 13 | struct A { void f() {}; }; 14 | void(A:: * p)() = &A::f; 15 | std::cout << std::is_member_function_pointer() << '\n';// true 16 | 17 | std::cout << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /Chapter 2/44 - my_decay.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | template struct my_decay { 7 | private: 8 | using U = remove_reference_t; 9 | public: 10 | using type = conditional_t, remove_extent_t*, 11 | conditional_t, add_pointer_t, 12 | remove_cv_t>>; 13 | }; 14 | 15 | int main() 16 | { 17 | std::cout << typeid(my_decay::type).name() << '\n'; // int 18 | std::cout << typeid(my_decay::type).name() << '\n'; // const int * 19 | 20 | 21 | std::cout << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 2/45 - copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for std::memcpy() 5 | 6 | // use the efficient memcpy() if allowed (i.e., T is trivially copyable): 7 | template 8 | typename std::enable_if::value>::type 9 | copy(T(&from)[N], T(&to)[N]) 10 | { 11 | std::memcpy(to, from, N * sizeof(T)); 12 | } 13 | 14 | // otherwise, copy elements one by one using copy assignment: 15 | template 16 | std::enable_if_t> 17 | copy(T(&from)[N], T(&to)[N]) 18 | { 19 | for (size_t i = 0; i < N; ++i) to[i] = from[i]; 20 | } 21 | 22 | int main() 23 | { 24 | int arrayFrom[12] = { 0 }; 25 | int arrayTo[12] = { 0 }; 26 | copy(arrayFrom, arrayTo); // Calls the first copy() implementation. 27 | 28 | std::string vecFrom[2] = { "A", "B" }; 29 | std::string vecTo[2]; 30 | copy(vecFrom, vecTo); // Calls the second copy() implementation. 31 | 32 | 33 | std::cout << std::endl; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter 2/46 - copy - constexpr if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for std::memcpy() 5 | 6 | template 7 | void copy(T(&from)[N], T(&to)[N]) 8 | { 9 | if constexpr (std::is_trivially_copyable_v) { 10 | std::memcpy(to, from, N * sizeof(T)); 11 | } else { 12 | for (size_t i = 0; i < N; ++i) to[i] = from[i]; 13 | } 14 | } 15 | 16 | 17 | int main() 18 | { 19 | int arrayFrom[12] = { 0 }; 20 | int arrayTo[12] = { 0 }; 21 | copy(arrayFrom, arrayTo); // Calls the first copy() implementation. 22 | 23 | std::string vecFrom[2] = { "A", "B" }; 24 | std::string vecTo[2]; 25 | copy(vecFrom, vecTo); // Calls the second copy() implementation. 26 | 27 | 28 | std::cout << std::endl; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter 2/47 - void_t.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template> 5 | struct has_value_type : std::false_type {}; 6 | 7 | template 8 | struct has_value_type> 9 | : std::true_type {}; 10 | 11 | template 12 | inline constexpr bool has_value_type_v = has_value_type::value; 13 | 14 | int main() 15 | { 16 | // All containers (Chapter 3) define a value_type type alias (example 17 | // needs the header), as does std::integral_constant itself: 18 | static_assert(has_value_type>::value); 19 | static_assert(!has_value_type_v); 20 | static_assert(has_value_type>{}); 21 | } 22 | -------------------------------------------------------------------------------- /Chapter 2/48 - declval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void process(const T& /*t*/) 6 | { 7 | if constexpr (std::is_integral_v().handle())>) 8 | std::cout << "handle() has integral return type\n"; 9 | else 10 | std::cout << "handle() has non-integral return type\n"; 11 | } 12 | 13 | struct NoDefaultCtor { NoDefaultCtor(int) {}; int handle(); }; 14 | struct DefaultCtor { std::string handle(); }; 15 | 16 | int main() 17 | { 18 | process(NoDefaultCtor{ 0 }); // handle() has integral return type 19 | process(DefaultCtor{}); // handle() has non-integral return type 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 2/49 - invoke.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void process(C callable, Args... args) 6 | { 7 | // ... Do stuff ... 8 | std::invoke(callable, std::forward(args)...); 9 | // ... Do more stuff ... 10 | } 11 | 12 | class Processor { 13 | public: 14 | void handle(int data) 15 | { 16 | std::cout << "Processor::handle()\n"; 17 | } 18 | }; 19 | 20 | void f(float data) 21 | { 22 | std::cout << "Global function f()\n"; 23 | } 24 | 25 | int main() 26 | { 27 | Processor processor; 28 | process(&f, 15.85714f); 29 | process(&Processor::handle, processor, 42); 30 | } 31 | -------------------------------------------------------------------------------- /Chapter 3/01 - non-member begin and end.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int myArray[] = { 1,2,3,4 }; 7 | const auto beginIter = std::cbegin(myArray); 8 | const auto endIter = std::cend(myArray); 9 | for (auto iter = beginIter; iter != endIter; ++iter) 10 | std::cout << *iter << std::endl; 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 3/02 - range-based for loop.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int myArray[] = { 1,2,3,4 }; 6 | for (const auto& element : myArray) 7 | std::cout << element << std::endl; 8 | 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 3/03 - vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../Common/Person.h" 5 | 6 | int main() 7 | { 8 | { 9 | std::vector myVector1 = { 1,2,3,4 }; 10 | std::vector myVector2{ 1,2,3,4 }; 11 | } 12 | 13 | 14 | { 15 | std::vector oneTwoThree{ 1,2,3 }; // deduced from initializer list 16 | std::vector fiveFloats(5, 0.f); // deduced from 0.f 17 | } 18 | 19 | 20 | { 21 | std::vector myVector(100, 12); 22 | 23 | myVector[1] = 22; 24 | std::cout << myVector[1] << '\n'; // 22 25 | } 26 | 27 | 28 | { 29 | std::vector myVector; 30 | myVector.push_back(11); 31 | myVector.push_back(2); 32 | } 33 | 34 | 35 | { 36 | std::vector myVector{ 1,2,3,4 }; 37 | myVector.insert(myVector.begin() + 2, 22); // 1,2,22,3,4 38 | } 39 | 40 | 41 | { 42 | std::vector myVector{ 1,2,3,4 }; 43 | for (auto iter = myVector.begin(); iter != myVector.end(); ++iter) 44 | { 45 | if (*iter % 2 == 0) // Duplicate all even values... 46 | iter = myVector.insert(iter + 1, *iter); 47 | } 48 | } 49 | 50 | 51 | { 52 | std::vector v1{ 1,2,3 }; 53 | std::vector v2{ 4,5 }; 54 | v1.insert(cbegin(v1) + 1, cbegin(v2), cend(v2)); // 1,4,5,2,3 55 | v1.insert(cend(v1), cbegin(v2), cend(v2)); // 1,4,5,2,3,4,5 (append!) 56 | 57 | 58 | v1.insert(cbegin(v1) + 1, { 4,5 }); // 1,4,5,2,3 59 | v1.insert(cend(v1), 2, 6); // 1,4,5,2,3,6,6 60 | } 61 | 62 | 63 | { 64 | std::vector persons; 65 | persons.push_back(Person("Sheldon", "Cooper")); 66 | persons.emplace_back("Leonard", "Hofstadter"); 67 | 68 | 69 | Person person("Howard", "Wolowitz"); 70 | persons.push_back(std::move(person)); 71 | } 72 | 73 | 74 | { 75 | std::vector myVector; 76 | myVector.resize(100, 12); 77 | 78 | 79 | myVector.reserve(100); 80 | 81 | 82 | myVector.reserve(myVector.size() + 100); 83 | } 84 | 85 | 86 | { 87 | std::vector unlucky(100000, 13); // Now reclaim unlucky's memory... 88 | { std::vector empty; empty.swap(unlucky); } 89 | 90 | 91 | std::vector().swap(unlucky); // (temporary is destroyed after ';') 92 | } 93 | 94 | 95 | { 96 | std::vector vec{ 1,2,3,2,2,6 }; 97 | for (auto it = cbegin(vec); it != cend(vec);) { 98 | if (*it == 2) 99 | it = vec.erase(it); // Returns iterator one past the removed item 100 | else 101 | ++it; 102 | } 103 | } 104 | 105 | 106 | { 107 | std::vector vec{ 1,2,3,2,2,6 }; // 1,2,3,2,2,6 108 | auto iter = std::remove(begin(vec), end(vec), 2); // 1,3,6,2,2,6 109 | vec.erase(iter, end(vec)); // 1,3,6 110 | 111 | 112 | vec.erase(std::remove(begin(vec), end(vec), 2), end(vec)); 113 | } 114 | 115 | 116 | std::cout << std::endl; 117 | } 118 | -------------------------------------------------------------------------------- /Chapter 3/04 - deque.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::deque myDeque{ 1,2,3,4 }; // std::deque deduced 7 | myDeque.insert(myDeque.begin() + 2, 22); // 1,2,22,3,4 8 | myDeque.pop_front(); // 2,22,3,4 9 | myDeque.erase(myDeque.begin() + 1); // 2,3,4 10 | myDeque.push_front(11); // 11,2,3,4 11 | 12 | 13 | std::cout << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 3/05 - array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | { 7 | std::array myArray; 8 | } 9 | 10 | 11 | { 12 | std::array myArray{ 1,2 }; // 1,2,0 13 | } 14 | 15 | 16 | { 17 | std::array myArray{ 1,2 }; // std::array deduced 18 | } 19 | 20 | 21 | { 22 | std::array myArray{}; // 0,0,0 23 | 24 | 25 | myArray.fill(5); // 5,5,5 26 | } 27 | 28 | 29 | std::cout << std::endl; 30 | } 31 | -------------------------------------------------------------------------------- /Chapter 3/06 - list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::list list1{ 1,7,5 }, list2{ 5,6,2 }, list3{ 3,4 }; // list 7 | list1.sort(); // 1,5,7 8 | list2.sort(); // 2,5,6 9 | list1.merge(list2); // list1 = 1,2,5,5,6,7 10 | // list2 = empty 11 | list1.unique(); // 1,2,5,6,7 12 | 13 | auto splicePosition = std::next(begin(list1), 2); 14 | list1.splice(splicePosition, list3); // list1 = 1,2,3,4,5,6,7 15 | // list3 = empty 16 | 17 | 18 | std::cout << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter 3/07 - size.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int array[]{ 1, 2, 3 }; 7 | std::cout << std::size(array) << std::endl; // 3 8 | 9 | // old-school alternative 10 | std::cout << sizeof(array) / sizeof(array[0]) << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 3/08 - bitset.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | { 7 | std::bitset<10> myBitset; 8 | } 9 | 10 | 11 | { 12 | std::bitset<4> myBitset("1001"); 13 | } 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 3/09 - Container Adapters.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../Common/Person.h" 5 | 6 | int main() 7 | { 8 | std::queue cont; 9 | cont.emplace("Doug", "B", true); 10 | cont.emplace("Phil", "W", false); 11 | cont.emplace("Stu", "P", true); 12 | cont.emplace("Alan", "G", false); 13 | while (!cont.empty()) 14 | { 15 | std::cout << cont.front() << std::endl; // queue 16 | // std::cout << cont.top() << std::endl; // priority_queue and stack 17 | cont.pop(); 18 | } 19 | 20 | 21 | std::cout << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 3/10 - map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | int main() 6 | { 7 | std::map myMap{ { Person("Jenne"), 1 },{ Person("Bart"), 2 } }; 8 | 9 | 10 | auto iter = begin(myMap); // type of *iter is pair& 11 | std::cout << "Key=" << iter->first.GetFirstName(); // Key=Bart 12 | std::cout << ", Value=" << iter->second << std::endl; // , Value=2 13 | 14 | 15 | myMap[Person("Bart")] = 0; 16 | std::cout << myMap[Person("Bart")] << std::endl; // 0 17 | 18 | 19 | myMap.erase(Person("Bart")); 20 | 21 | 22 | myMap[Person("Peter")] = 3; 23 | 24 | 25 | myMap.insert(std::pair(Person("Marc"), 4)); 26 | myMap.insert({ Person("Marc"), 4 }); 27 | 28 | 29 | myMap.insert({ Person("Marc"), 5 }); // 5 is discarded 30 | std::cout << myMap[Person("Marc")] << std::endl; // still 4! 31 | 32 | 33 | myMap.insert_or_assign(Person("Marc"), 5); 34 | std::cout << myMap[Person("Marc")] << std::endl; // 5 35 | 36 | 37 | std::map inverseMap; 38 | inverseMap.insert({ 3, Person("Peter", "Van Weert") }); 39 | inverseMap.insert_or_assign(5, Person("Marc", "Gregoire")); 40 | 41 | 42 | inverseMap.emplace(6, Person("Christophe", "Pichaud")); 43 | inverseMap.emplace(std::piecewise_construct, std::forward_as_tuple(6), 44 | std::forward_as_tuple("Christophe", "Pichaud")); 45 | inverseMap.try_emplace(6, "Christophe", "Pichaud"); 46 | 47 | 48 | Person powers("Mark", "Powers"); 49 | inverseMap.emplace(6, std::move(powers)); 50 | 51 | 52 | { 53 | auto [iter, inserted] = inverseMap.insert({ 6, Person("Marc") }); 54 | if (!inserted) 55 | std::cout << "Not inserted. Existing value: " << iter->second; 56 | } 57 | 58 | 59 | std::cout << std::endl; 60 | } 61 | -------------------------------------------------------------------------------- /Chapter 3/11 - multimap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::multimap myMulti; 8 | myMulti.insert({ "someKey", 2 }); 9 | myMulti.insert({ "sameKey", 5 }); 10 | myMulti.insert({ "sameKey", 2 }); 11 | std::cout << myMulti.size() << ' ' << myMulti.begin()->second; // 3 5 12 | 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 3/12 - set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::set mySet{ 3,2,1 }; // std::set deduced 7 | mySet.insert(2); 8 | mySet.insert(6); 9 | std::cout << mySet.size() << ' ' << *mySet.begin(); // 4 1 10 | 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 3/13 - moving nodes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | int main() 6 | { 7 | std::map myMap{ { Person("Marc"), 1 }, { Person("Bart"), 2 } }; 8 | std::map myOtherMap; 9 | 10 | auto node = myMap.extract(Person("Marc")); // type std::map::node_type 11 | if (node) // or: !node.empty() 12 | myOtherMap.insert(std::move(node)); // would ignore empty node 13 | 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 3/14 - merging.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::multiset src{ 1, 2, 4 }; 7 | std::set dst{ 2, 3 }; 8 | dst.merge(src); 9 | // src == { 2 } 10 | // dst == { 1, 2, 3, 4 } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 3/15 - hash - Person.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | namespace std { 6 | template<> struct hash { 7 | // The requirement to add the following two type aliases 8 | // is deprecated in C++17 (and expected to be removed in C++20) 9 | using argument_type = Person; 10 | using result_type = std::size_t; 11 | 12 | result_type operator()(const argument_type& p) const { 13 | auto firstNameHash(std::hash()(p.GetFirstName())); 14 | auto lastNameHash(std::hash()(p.GetLastName())); 15 | return firstNameHash ^ lastNameHash; 16 | } 17 | }; 18 | } 19 | 20 | int main() 21 | { 22 | std::unordered_set persons; 23 | persons.insert(Person("John", "Doe")); 24 | } 25 | -------------------------------------------------------------------------------- /Chapter 3/16 - allocators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | 6 | int main() 7 | { 8 | std::allocator allocator; // Default allocator 9 | Person* p = allocator.allocate(1); // Person constructor not invoked 10 | new(p) Person("Basil", "Fawlty"); // Initialize using placement new 11 | p->~Person(); // Memory not deallocated yet 12 | allocator.deallocate(p, 1); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 3/17 - memory resources.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int main() 8 | { 9 | char buffer[300]; // Static allocation on the stack 10 | std::pmr::monotonic_buffer_resource resource( 11 | buffer, std::size(buffer), std::pmr::null_memory_resource() 12 | ); 13 | std::pmr::string short_string(&resource); 14 | // ... fill and manipulate short_string 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 4/01 - transform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::vector vec{ 1,2,3,4,5,6 }; 9 | 10 | std::transform(cbegin(vec), cend(vec), begin(vec), 11 | [](auto & element) { return element * 2; }); 12 | 13 | std::transform(cbegin(vec), cend(vec), begin(vec), std::negate<>()); 14 | 15 | std::for_each(begin(vec), end(vec), [](int& i) { i += 1; }); 16 | 17 | std::for_each_n(cbegin(vec), size(vec), 18 | [](const auto & element) { std::cout << element << " "; }); 19 | 20 | 21 | std::cout << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 4/02 - all_of.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 1,2,3,4,5,6 }; 8 | bool allEven = std::all_of(cbegin(vec), cend(vec), 9 | [](auto & element) { return element % 2 == 0; }); // false 10 | std::cout << allEven << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 4/03 - find_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../Common/Person.h" 5 | 6 | int main() 7 | { 8 | auto people = { Person("Wally"), Person("Wilma"), Person("Wenda"), 9 | Person("Odlaw"), Person("Waldo"), Person("Woof") }; 10 | auto iter = std::find_if(begin(people), end(people), 11 | [](const Person & p) { return p.GetFirstName() == "Waldo"; }); 12 | std::cout << iter->GetFirstName() << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 4/04 - lower_bound.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 11,22,33 }; 8 | const int valueToAdd = 18; 9 | auto lower = std::lower_bound(cbegin(vec), cend(vec), valueToAdd); 10 | vec.insert(lower, valueToAdd); // 11,18,22,33 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 4/05 - equal_range.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 1,2,2,3,4 }; 8 | auto result = std::equal_range(cbegin(vec), cend(vec), 2); 9 | vec.erase(result.first, result.second); // 1,3,4 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 4/06 - searching.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::string needle = "hat"; 9 | std::string stack = "Burn the haystack. What's left is the needle."; 10 | const std::boyer_moore_searcher searcher(begin(needle), end(needle)); 11 | const auto found = std::search(begin(stack), end(stack), searcher); 12 | std::cout << "Found at position " << std::distance(begin(stack), found); 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 4/07 - generate and iota.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::vector vec(6); // 0,0,0,0,0,0 9 | int value = 11; 10 | std::generate(begin(vec), begin(vec) + 3, 11 | [&value] { value *= 2; return value; }); // 22,44,88,0,0,0 12 | std::iota(begin(vec) + 3, end(vec), 2); // 22,44,88,2,3,4 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 4/08 - copy_if.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::vector numbers{ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 }; 9 | std::vector evens(numbers.size()); 10 | auto end = std::copy_if(cbegin(numbers), cend(numbers), begin(evens), 11 | [](int x) { return x % 2 == 0; }); 12 | evens.erase(end, evens.end()); // 2 8 34 144 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 4/09 - unique.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector v{ 3,4,4,4,5,6,4,5,5,7 }; 8 | auto result = std::unique(begin(v), end(v)); // possible outcome: 3,4,5,6,4,5,7,5,5,7 9 | v.erase(result, end(v)); // final outcome: 3,4,5,6,4,5,7 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 4/10 - rotate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 1,2,3,4,5,6 }; 8 | std::rotate(begin(vec), begin(vec) + 4, end(vec)); 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 4/11 - partial_sort_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 9,2,4,7,3,6,1 }; 8 | std::vector threeSmallestElements(3); 9 | std::partial_sort_copy(begin(vec), end(vec), 10 | begin(threeSmallestElements), end(threeSmallestElements)); 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 4/12 - nth_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 9,2,4,7,3,6,1 }; 8 | auto middle = begin(vec) + vec.size() / 2; 9 | std::nth_element(begin(vec), middle, end(vec)); 10 | int median = *middle; // 4 11 | std::cout << median << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 4/13 - shuffle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | std::random_device seeder; 10 | const auto seed = seeder.entropy() ? seeder() : std::time(nullptr); 11 | std::default_random_engine gen( 12 | static_cast(seed)); 13 | std::vector in{ 1,2,3,4,5,6,7,8,9,10 }; 14 | std::vector out(6); 15 | std::sample(begin(in), end(in), begin(out), size(out), gen); // Possible result: 1 3 4 7 9 10 16 | std::shuffle(begin(out), end(out), gen); // Possible result: 3 10 9 7 4 1 17 | 18 | std::cout << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter 4/14 - reduce.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 4,2,5,1,3,6 }; 8 | int sum = std::reduce(begin(vec), end(vec)); // 21 9 | std::cout << sum << std::endl; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter 4/15 - inner_product.cpp: -------------------------------------------------------------------------------- 1 | #define _SCL_SECURE_NO_WARNINGS // To make the example work in Visual C++. 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | double v1[] = { 0,1,2 }; 9 | double v2[] = { 1,0,2 }; 10 | double dot = std::inner_product(std::begin(v1), std::end(v1), 11 | std::begin(v2), 0.0); // 0*1 + 1*0 + 2*2 = 4.0 12 | 13 | std::cout << dot << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 4/16 - parallel sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::vector largeVector{ 22,11,66,33,22,1,5,9,8,22 }; 9 | using namespace std::execution; 10 | std::sort(par, begin(largeVector), end(largeVector)); 11 | 12 | 13 | std::cout << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 4/17 - Iterator Adaptors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | std::vector nums{ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 }; 10 | std::vector evens; 11 | auto is_even = [](int x) { return x % 2 == 0; }; 12 | std::copy_if(cbegin(nums), cend(nums), back_inserter(evens), is_even); 13 | 14 | 15 | std::set odds; 16 | std::remove_copy_if(cbegin(nums), cend(nums), 17 | inserter(odds, begin(odds)), is_even); 18 | 19 | 20 | std::cout << std::endl; 21 | } 22 | -------------------------------------------------------------------------------- /Chapter 5/01 - Manipulators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | using namespace std; 8 | cout.imbue(locale("")); // Use the user's preferred locale, see Chapter 6 9 | cout << setfill('_') << hex << showbase; 10 | cout << "Left: " << left << setw(7) << put_money(123) << '\n'; 11 | cout << "Right: " << right << setw(7) << put_money(123) << '\n'; 12 | cout << "Internal: " << internal; 13 | cout.width(7); 14 | cout << 123 << '\n'; 15 | 16 | 17 | std::cout << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /Chapter 5/02 - Error Handling.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | { 7 | std::ifstream in("nonexistent_file.ext"); 8 | std::cout << in.fail() << std::endl; // 1 9 | } 10 | 11 | 12 | { 13 | std::ifstream in("nonexistent_file.ext"); 14 | try { 15 | in.exceptions(std::ios_base::failbit); // Raise exceptions on failure 16 | } catch (const std::ios_base::failure & exception) { 17 | std::cout << exception.what() << std::endl; 18 | } 19 | } 20 | 21 | 22 | std::cout << std::endl; 23 | } 24 | -------------------------------------------------------------------------------- /Chapter 5/03 - ostream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout << "PI = " << 3.1415 << std::endl; 6 | std::cout.put('\t'); 7 | std::cout.write("C++", 3); 8 | 9 | 10 | std::cout << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 5/04 - istream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int anInt; 7 | double aDouble; 8 | std::cout << "Enter an integer followed by some whitespace\n" 9 | << "and a double, and press enter: "; 10 | std::cin >> anInt >> aDouble; 11 | std::cout << "You entered: "; 12 | std::cout << "Integer = " << anInt << ", Double = " << aDouble 13 | << std::endl; 14 | 15 | std::string message; 16 | std::cout << "Enter a string. End input with a * and enter: "; 17 | std::getline(std::cin >> std::ws, message, '*'); 18 | std::cout << "You entered: '" << message << "'" << std::endl; 19 | 20 | 21 | std::cout << std::endl; 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 5/05 - sstream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::ostringstream oss; 8 | oss << 123 << " " << 3.1415; 9 | std::string myString = oss.str(); 10 | std::cout << "ostringstream contains: '" << myString << "'" << std::endl; 11 | 12 | std::istringstream iss(myString); 13 | int myInt; double myDouble; 14 | iss >> myInt >> myDouble; 15 | std::cout << "int = " << myInt << ", double = " << myDouble << std::endl; 16 | 17 | 18 | std::cout << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter 5/06 - fstream - input and output.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::string filename = "data.txt"; 7 | std::fstream fs(filename); // Default openmode=ios_base::in|ios_base::out 8 | if (!fs.good()) { // Fail bit will be set if file does not exist 9 | fs.clear(); // First clear the error state 10 | fs.open(filename, std::ios_base::out); // Create the file 11 | fs.close(); // Close and reopen the file for input and output 12 | fs.open(filename, std::ios_base::in | std::ios_base::out); 13 | } 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 5/07 - fstream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | const std::string filename = "output.txt"; 8 | std::ofstream ofs(filename); 9 | ofs << 123 << " " << 3.1415; 10 | ofs.close(); 11 | 12 | std::ifstream ifs(filename); 13 | int myInt; double myDouble; 14 | ifs >> myInt >> myDouble; 15 | std::cout << "int = " << myInt << ", double = " << myDouble << std::endl; 16 | 17 | 18 | std::cout << std::endl; 19 | } 20 | -------------------------------------------------------------------------------- /Chapter 5/08 - Custom Output and Extraction Operator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class Person { 7 | public: 8 | Person() = default; 9 | explicit Person(std::string first, std::string last = "", 10 | bool isVIP = false) 11 | : m_first(move(first)), m_last(move(last)), m_isVIP(isVIP) {} 12 | 13 | const std::string& GetFirstName() const { return m_first; } 14 | void SetFirstName(std::string first) { m_first = move(first); } 15 | 16 | const std::string& GetLastName() const { return m_last; } 17 | void SetLastName(std::string last) { m_last = move(last); } 18 | 19 | bool IsVIP() const { return m_isVIP; } 20 | 21 | private: 22 | std::string m_first, m_last; 23 | bool m_isVIP = false; 24 | }; 25 | 26 | // Comparison operator 27 | bool operator<(const Person& lhs, const Person& rhs) { 28 | if (lhs.IsVIP() != rhs.IsVIP()) return rhs.IsVIP(); 29 | if (lhs.GetLastName() != rhs.GetLastName()) 30 | return lhs.GetLastName() < rhs.GetLastName(); 31 | return lhs.GetFirstName() < rhs.GetFirstName(); 32 | } 33 | 34 | // Equality operator 35 | bool operator==(const Person & lhs, const Person & rhs) { 36 | return lhs.IsVIP() == rhs.IsVIP() 37 | && lhs.GetFirstName() == rhs.GetFirstName() 38 | && lhs.GetLastName() == rhs.GetLastName(); 39 | } 40 | 41 | std::ostream& operator<<(std::ostream& out, const Person& person) { 42 | return out << std::quoted(person.GetFirstName()) << ' ' 43 | << std::quoted(person.GetLastName()); 44 | } 45 | 46 | std::istream& operator>>(std::istream& in, Person& person) { 47 | std::string firstName, lastName; 48 | in >> std::quoted(firstName) >> std::quoted(lastName); 49 | if (firstName.empty()) // fail if invalid data is read 50 | in.setstate(std::ios::failbit); // add fail bit 51 | else if (in) // only if reading succeeded 52 | person = Person(std::move(firstName), std::move(lastName)); 53 | return in; 54 | } 55 | 56 | int main() 57 | { 58 | Person kurt("Kurt", "von Strohm"); 59 | std::stringstream ss; 60 | ss << kurt; 61 | std::cout << ss.str() << '\n'; // "Kurt" "von Strohm" 62 | ss.seekg(0); // Seek back to beginning of stream 63 | Person readBack; 64 | ss >> readBack; 65 | std::cout << readBack << '\n'; // "Kurt" "von Strohm" 66 | 67 | 68 | std::cout << std::endl; 69 | } 70 | -------------------------------------------------------------------------------- /Chapter 5/09 - Custom Manipulators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class Person { 7 | public: 8 | Person() = default; 9 | explicit Person(std::string first, std::string last = "", 10 | bool isVIP = false) 11 | : m_first(move(first)), m_last(move(last)), m_isVIP(isVIP) {} 12 | 13 | const std::string& GetFirstName() const { return m_first; } 14 | void SetFirstName(std::string first) { m_first = move(first); } 15 | 16 | const std::string& GetLastName() const { return m_last; } 17 | void SetLastName(std::string last) { m_last = move(last); } 18 | 19 | bool IsVIP() const { return m_isVIP; } 20 | 21 | private: 22 | std::string m_first, m_last; 23 | bool m_isVIP = false; 24 | }; 25 | 26 | // Comparison operator 27 | bool operator<(const Person& lhs, const Person& rhs) { 28 | if (lhs.IsVIP() != rhs.IsVIP()) return rhs.IsVIP(); 29 | if (lhs.GetLastName() != rhs.GetLastName()) 30 | return lhs.GetLastName() < rhs.GetLastName(); 31 | return lhs.GetFirstName() < rhs.GetFirstName(); 32 | } 33 | 34 | // Equality operator 35 | bool operator==(const Person & lhs, const Person & rhs) { 36 | return lhs.IsVIP() == rhs.IsVIP() 37 | && lhs.GetFirstName() == rhs.GetFirstName() 38 | && lhs.GetLastName() == rhs.GetLastName(); 39 | } 40 | 41 | const int dot_xalloc = std::ios_base::xalloc(); // global constant 42 | 43 | // I/O manipulators that toggle the 'dot' field of a stream 44 | std::ios_base& dot(std::ios_base& stream) { 45 | stream.iword(dot_xalloc) = 1; return stream; 46 | } 47 | std::ios_base& nodot(std::ios_base& stream) { 48 | stream.iword(dot_xalloc) = 0; return stream; 49 | } 50 | 51 | // Output stream operator that 'dots' the first name if requested 52 | std::ostream& operator<<(std::ostream& out, const Person& person) { 53 | if (out.iword(dot_xalloc)) 54 | out << person.GetFirstName().front() << '.'; 55 | else 56 | out << person.GetFirstName(); 57 | return out << ' ' << person.GetLastName(); 58 | } 59 | 60 | std::istream& operator>>(std::istream& in, Person& person) { 61 | std::string firstName, lastName; 62 | in >> std::quoted(firstName) >> std::quoted(lastName); 63 | if (firstName.empty()) // fail if invalid data is read 64 | in.setstate(std::ios::failbit); // add fail bit 65 | else if (in) // only if reading succeeded 66 | person = Person(std::move(firstName), std::move(lastName)); 67 | return in; 68 | } 69 | 70 | int main() 71 | { 72 | Person person("Hubert", "Gruber"); 73 | std::cout << person << '\n' << dot << person << std::endl; 74 | 75 | std::cout << std::endl; 76 | } 77 | -------------------------------------------------------------------------------- /Chapter 5/10 - ostream_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::vector vec{ 1.11, 2.22, 3.33, 4.44 }; 8 | std::copy(cbegin(vec), cend(vec), 9 | std::ostream_iterator(std::cout, "\t")); 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 5/11 - istream_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::istream_iterator begin(std::cin), end; 8 | double sum = 0.0; int count = 0; 9 | std::for_each(begin, end, [&](double value) { sum += value; ++count; }); 10 | std::cout << sum / count << std::endl; 11 | 12 | 13 | std::cout << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 5/12 - Stream Iterators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::ostringstream oss; 8 | std::istream_iterator begin(std::cin), end; 9 | std::copy(begin, end, std::ostream_iterator(oss, "\t")); 10 | std::cout << oss.str() << std::endl; 11 | 12 | 13 | std::cout << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 5/13 - Stream Buffers - Redirect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::ofstream file("output.txt"); 7 | auto oldCoutBuf = std::cout.rdbuf(file.rdbuf()); // Redirect cout to file 8 | std::cout << "Some output" << '\n'; // Write to file 9 | std::cout.rdbuf(oldCoutBuf); // Restore the old cout buffer! 10 | 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 5/14 - Stream Buffers - Read File.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::ifstream ifs("test.txt"); 8 | std::stringstream buffer; 9 | buffer << ifs.rdbuf(); 10 | 11 | 12 | std::cout << std::endl; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 5/15 - filesystem - decomposition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::filesystem::path my_path("c:/Windows/notepad.exe"); 7 | for (const std::filesystem::path& element : my_path) 8 | std::cout << element << ", "; 9 | 10 | 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /Chapter 5/16 - filesystem - filename.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | using std::filesystem::path; 7 | std::cout << path(R"(c:\Temp)").filename() << std::endl; // "Temp" 8 | std::cout << path(R"(c:\Temp\)").filename() << std::endl; // "" 9 | } 10 | -------------------------------------------------------------------------------- /Chapter 5/17 - filesystem - composition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | auto get_full_path(int ind) { 5 | auto temp_dir = std::filesystem::path(LR"(c:\temp)"); 6 | auto full_path = temp_dir / u8"file"; // or "file", L"file", etc. 7 | full_path += std::to_string(ind) + ".log";// or full_path.append(...); 8 | return full_path; 9 | } 10 | 11 | int main() 12 | { 13 | std::cout << get_full_path(10) << std::endl; 14 | 15 | using std::filesystem::path; 16 | std::cout << path("foo") / "bar" << '\n'; // "foo/bar" or "foo\\bar" 17 | std::cout << path("foo") / "/bar" << '\n'; // "/bar" 18 | std::cout << path("foo") / "c:/bar" << '\n'; // "c:/bar" (Windows) 19 | std::cout << path("c:/foo") / "d:bar" << '\n'; // "d:bar" (Windows) 20 | std::cout << path("c:/foo") / "c:bar" << '\n'; // "c:/foo\\bar" (Windows) 21 | std::cout << path("c:/foo") / "/bar" << '\n'; // "c:/bar" (Windows) 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 5/18 - filesystem - directory listing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | // Print the names of all regular files in the current directory 7 | std::filesystem::directory_iterator begin("."), end; 8 | for (auto iter = begin; iter != end; ++iter) { 9 | if (iter->is_regular_file()) { 10 | std::cout << iter->path().filename() << '\n'; 11 | } 12 | } 13 | 14 | 15 | std::cout << std::endl; 16 | 17 | 18 | for (auto& entry : std::filesystem::directory_iterator(".")) { 19 | if (entry.is_regular_file()) { 20 | std::cout << entry.path().filename() << '\n'; 21 | } 22 | } 23 | 24 | 25 | std::cout << std::endl; 26 | 27 | 28 | for (auto& entry : std::filesystem::recursive_directory_iterator(".")) { 29 | if (entry.is_regular_file()) { 30 | std::cout << entry.path().filename() << '\n'; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Chapter 5/19 - printf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | std::string bottles = "bottles of beer"; 9 | char on_wall[99]; 10 | for (int i = 99; i > 0; --i) { 11 | snprintf(on_wall, sizeof(on_wall), "%s on the wall", bottles.c_str()); 12 | printf("%d %s, %d %s.\n", i, on_wall, i, bottles.c_str()); 13 | printf("Take one down, pass it around, %d %s.\n", i - 1, on_wall); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 5/20 - printf - Formatting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | int i = 123; 9 | std::printf("i: '%+10d'\n", i); // i: ' +123' 10 | 11 | long double d = 31.415; 12 | int prec = 4; /* precision */ 13 | std::printf("d: %.4Lf = %.*Le\n", d, prec, d); // d: 31.4150 = 3.1415e+01 14 | } 15 | -------------------------------------------------------------------------------- /Chapter 5/21 - scanf.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS // To make the example work with Visual C++. 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::string s = "i: +123; d: -2.34E-3; chars: abcdef"; 8 | int i = 0; double d = 0.0; char chars[4] = { 0 }; 9 | std::sscanf(s.c_str(), "i: %i; d: %lE; chars: %[abc]", &i, &d, chars); 10 | std::printf("i: %+i; d: %.2lE; chars: %s", i, d, chars); 11 | 12 | std::printf("\n"); 13 | } 14 | -------------------------------------------------------------------------------- /Chapter 6/01 - string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | { 9 | std::string s = "Strings be fun"; 10 | s.reserve(20); 11 | s.push_back('!'); // "Strings be fun!" 12 | const auto found = std::find(begin(s), end(s), 'b'); 13 | s[found - s.cbegin()] = 'r'; // "Strings re fun!" 14 | s.insert(found, 'a'); // "Strings are fun!" 15 | } 16 | 17 | 18 | { 19 | std::string s = "Strings be fun"; 20 | s.reserve(20); 21 | s.push_back('!'); // "Strings be fun!" 22 | const size_t found = s.find('b'); 23 | s[found] = 'r'; 24 | s.insert(found, "a"); // (no index-based single-character insert exists) 25 | } 26 | 27 | 28 | { 29 | std::string s = "Strings be fun"; 30 | s.reserve(20); 31 | s.push_back('!'); // "Strings be fun!" 32 | const size_t found = s.find("be"); 33 | s.replace(found, 2, "are"); // 2 = number of characters to replace 34 | } 35 | 36 | 37 | { 38 | using namespace std::literals::string_literals; 39 | auto a = "a is a const char*"; 40 | auto b = "b is a std::string"s; 41 | auto c = std::pair(3u, L"c is a pair"s); // 42 | } 43 | 44 | 45 | { 46 | std::string s(u8"字符串"); // UTF-8 encoding of Chinese word for "string" 47 | std::cout << s.length(); // Length: 9 code units! 48 | } 49 | 50 | 51 | std::cout << std::endl; 52 | } 53 | -------------------------------------------------------------------------------- /Chapter 6/02 - string_view.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string_view extension(std::string_view fileName) { 5 | return fileName.substr(fileName.rfind('.') + 1); 6 | } 7 | 8 | int main() 9 | { 10 | std::cout << extension("myfile.txt") << std::endl; 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 6/03 - codecvt.cpp: -------------------------------------------------------------------------------- 1 | #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1 // For Visual Studio 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Inherit all constructors and make a protected destructor public: 10 | template 11 | class Deletable : public BASE { 12 | public: 13 | using BASE::BASE; 14 | ~Deletable() = default; 15 | }; 16 | 17 | 18 | int main() 19 | { 20 | std::string s(u8"字符串"); // UTF-8 encoding of Chinese word for "string" 21 | std::cout << s.length(); // Length: 9 code units! 22 | 23 | /* Does not compile. See text for the explanation. 24 | { 25 | using cvt = std::codecvt; 26 | std::wstring_convert convertor; 27 | std::u32string s_u32 = convertor.from_bytes(s); 28 | std::cout << s_u32.length(); // Length: 3 code units 29 | } 30 | */ 31 | 32 | 33 | { // Does not work in Visual C++ 2019. See text. 34 | using cvt = Deletable>; 35 | std::wstring_convert convertor; 36 | std::u32string s_u32 = convertor.from_bytes(s); 37 | std::cout << s_u32.length(); // Length: 3 code units 38 | } 39 | 40 | 41 | { // Does not work in Visual C++ 2019. See text. 42 | using cvt = Deletable>; 43 | std::wstring_convert convertor(new cvt("")); 44 | std::u32string s_u32 = convertor.from_bytes(s); 45 | std::cout << s_u32.length(); // Length: 3 code units 46 | } 47 | 48 | 49 | { // Works fine with Visual C++ 2019. 50 | std::ofstream out("test.txt"); // char-based file output stream 51 | std::wbuffer_convert> cvt(out.rdbuf()); 52 | std::wostream wout(&cvt); // wchar_t output stream 53 | wout << L"I am written as UTF-8, irrespective of the native wide format!"; 54 | } 55 | 56 | std::cout << std::endl; 57 | } 58 | -------------------------------------------------------------------------------- /Chapter 6/04 - Global Locale.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::locale current_locale; 7 | std::cout << '"' << current_locale.name() << '"' << '\n'; // "C" 8 | std::cout << 100000 << '\n'; // 100000 9 | std::locale::global(std::locale("")); // Global locale -> user preferences 10 | std::cout << 100000 << '\n'; // 100000 11 | std::cout.imbue(std::locale()); // Imbue the current global locale 12 | std::cout << 100000 << '\n'; // Some possible outputs (locale dependent): 13 | // 100,000; 100 000; 100.000; 1,00,000; ... 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 6/05 - use_facet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | const auto& f = std::use_facet>(std::locale::classic()); 7 | std::cout << f.decimal_point() << std::endl; // Prints a dot ('.') 8 | } 9 | -------------------------------------------------------------------------------- /Chapter 6/06 - Monetary Formatting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | std::locale my_locale("en-US"); // For Windows; for Linux use "en_US" 9 | std::stringstream stream; 10 | stream.imbue(my_locale); 11 | 12 | // Perform equivalent of 'stream << std::put_money(valueIn);' explicitly: 13 | long double valueIn = 123456; // (Or: 'std::string valueIn = "123456";') 14 | auto& money_formatter = std::use_facet>(my_locale); 15 | stream << std::showbase; 16 | auto target = std::ostreambuf_iterator(stream); 17 | money_formatter.put(target, false, stream, ' ', valueIn); // $1,234.56 18 | 19 | // Perform equivalent of 'stream >> std::get_money(valueOut);' explicitly 20 | long double valueOut; // (Or: 'std::string valueOut;') 21 | auto& money_parser = std::use_facet>(my_locale); 22 | std::ios_base::iostate error = std::ios_base::goodbit; 23 | auto b = std::istreambuf_iterator(stream); 24 | auto e = std::istreambuf_iterator(); 25 | money_parser.get(b, e, false, stream, error, valueOut); // 123456 26 | if (error != std::ios_base::goodbit) stream.setstate(error); 27 | 28 | assert(valueIn == valueOut); 29 | 30 | 31 | std::cout << std::endl; 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 6/07 - String Ordering.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/cpp17-standard-library-quick-ref/cd62302142a290a438178541c8646f39d3054143/Chapter 6/07 - String Ordering.cpp -------------------------------------------------------------------------------- /Chapter 6/08 - Combining Facets.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() 8 | { 9 | int bigValue = 10000; 10 | long double money = 123456; 11 | cout << bigValue << " " << put_money(money) << '\n'; // 10000 123456 12 | 13 | locale chinese("zh_CN"); // For Windows use "zh-CN" 14 | cout.imbue(chinese); 15 | cout << bigValue << ' ' << put_money(money) << '\n'; // 10,000 1,234.56 16 | 17 | // Use the neutral "C" locale, but with Chinese monetary punctuation: 18 | locale combined = locale::classic().combine>(chinese); 19 | // Or: 20 | // locale combined(locale::classic(), &use_facet>(chinese)); 21 | // Or: 22 | // locale combined(locale::classic(), chinese, locale::monetary); 23 | cout.imbue(combined); 24 | cout << bigValue << ' ' << put_money(money) << '\n'; // 10000 1,234.56 25 | 26 | 27 | std::cout << std::endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter 6/09 - Custom Facets - yes_no.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class yes_no_numpunct : public std::numpunct { 5 | protected: 6 | virtual string_type do_truename() const override { return "yes"; } 7 | virtual string_type do_falsename() const override { return "no"; } 8 | }; 9 | 10 | int main() 11 | { 12 | std::cout.imbue(std::locale(std::cout.getloc(), new yes_no_numpunct)); 13 | std::cout << std::boolalpha << true << " / " << false << std::endl; 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 6/10 - Custom Facets - Accounting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class accounting_moneypunct : public std::moneypunct_byname { 6 | public: 7 | accounting_moneypunct(const std::string& name) 8 | : moneypunct_byname(name) { } 9 | protected: 10 | // Put negative numbers between parentheses: 11 | virtual string_type do_negative_sign() const override { return "()"; } 12 | // Override formats to facilitate accounting-style padding: 13 | static pattern acc_format() { return { symbol, space, sign, value }; } 14 | virtual pattern do_neg_format() const override { return acc_format(); } 15 | virtual pattern do_pos_format() const override { return acc_format(); } 16 | }; 17 | 18 | int main() 19 | { 20 | const auto name = "en_US"; // en-US on Windows. 21 | std::locale my_locale(std::locale(name), new accounting_moneypunct(name)); 22 | std::cout.imbue(my_locale); 23 | std::cout << std::showbase << std::internal; //show $ sign + tweak padding 24 | for (auto val : { 100000, -500 }) 25 | std::cout << std::setw(12) << std::put_money(val) << '\n'; 26 | 27 | 28 | std::cout << std::endl; 29 | } 30 | -------------------------------------------------------------------------------- /Chapter 6/11 - C Locales.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | // Use the user's preferred locale settings, 8 | // but with neutral numeric and monetary formatting 9 | std::locale::global(std::locale(std::locale(""), "C", 10 | std::locale::numeric | std::locale::monetary)); 11 | std::setlocale(LC_ALL, ""); 12 | std::setlocale(LC_NUMERIC, "C"); 13 | std::setlocale(LC_MONETARY, "C"); 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 6/12 - regex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::regex pattern(R"(<(.+)>(.*?))"); 8 | std::string target = "Bold, not bold, bold again."; 9 | 10 | std::cout << std::boolalpha; // print true/false instead of 1/0 11 | std::cout << std::regex_match(target, pattern) << "\n\n"; // false 12 | 13 | { 14 | std::smatch results; 15 | auto begin = target.cbegin(), end = target.cend(); 16 | while (std::regex_search(begin, end, results, pattern)) { 17 | std::cout << results.str(2) << '\n'; // "Bold", then "bold again" 18 | begin += results.length(); 19 | } 20 | } 21 | 22 | 23 | { 24 | std::sregex_iterator begin(target.cbegin(), target.cend(), pattern), 25 | end; // default constructor creates end-iterator 26 | std::for_each(begin, end, [](auto& results) { /* const std::smatch& */ 27 | std::cout << results.str(2) << '\n'; 28 | }); 29 | } 30 | 31 | 32 | { 33 | std::sregex_token_iterator beg(target.cbegin(), target.cend(), pattern, 2), 34 | end; // default constructor creates end-iterator 35 | std::for_each(beg, end, [](auto& subMatch) { /* const std::ssub_match& */ 36 | std::cout << subMatch << '\n'; 37 | }); 38 | } 39 | 40 | 41 | std::cout << std::endl; 42 | } 43 | -------------------------------------------------------------------------------- /Chapter 6/13 - Tokenizing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | const std::string csv = "a, b, c,123"; 8 | const std::regex regex(R"(\s*,\s*)"); 9 | std::sregex_token_iterator beg(begin(csv), end(csv), regex, -1), end; 10 | std::for_each(beg, end, [](auto & token) { std::cout << token << '\n'; }); 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 6/14 - regex_replace.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::regex vowels("[aeiou]"); 8 | std::cout << std::regex_replace("devoweled", vowels, "*") << '\n'; 9 | 10 | std::regex bolds("(.*?)"); 11 | std::string target = "debolded"; 12 | std::ostream_iterator out(std::cout); 13 | std::regex_replace(out, target.cbegin(), target.cend(), bolds, "$1"); 14 | 15 | 16 | std::cout << std::endl; 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 7/01 - Threads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void my_callable(const std::string& str, int i) 6 | { 7 | /* ... */ 8 | } 9 | 10 | int main() 11 | { 12 | int anotherArg = 42; 13 | std::thread worker1(my_callable, "arg", anotherArg); 14 | std::thread worker2([=] { my_callable("arg", anotherArg); }); 15 | 16 | worker1.join(); // See text. 17 | worker2.join(); // See text. 18 | 19 | std::cout << std::endl; 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 7/02 - Joining.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | double someExpensiveComputation() 6 | { 7 | return 4.2; 8 | } 9 | 10 | int main() 11 | { 12 | double result; 13 | std::thread worker([&result] { result = someExpensiveComputation(); }); 14 | // ... 15 | worker.join(); 16 | std::cout << result << std::endl; // Safe to use result now (see later) 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 7/03 - Futures.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int gcd(int x, int y) { return y ? gcd(y, x % y) : x; } // Euclid's algorithm 5 | 6 | int main() 7 | { 8 | { 9 | // std::async 10 | std::future answer = std::async(gcd, 123, 6); 11 | // ... 12 | std::cout << answer.get() << '\n'; // 3 (greatest common divisor of 123 and 6) 13 | } 14 | 15 | 16 | { 17 | // std::packaged_task 18 | std::packaged_task gcd_task(gcd); 19 | auto gcd_future = gcd_task.get_future(); // type: std::future 20 | std::thread worker(std::move(gcd_task), 8, 12); 21 | worker.detach(); 22 | // ... 23 | const int four = gcd_future.get(); 24 | std::cout << four << '\n'; 25 | } 26 | 27 | 28 | { 29 | // make_ready_at_thread_exit 30 | std::packaged_task gcd_task(gcd); 31 | std::thread worker([&] { gcd_task.make_ready_at_thread_exit(8, 12); }); 32 | worker.detach(); 33 | // ... 34 | const int four = gcd_task.get_future().get(); 35 | std::cout << four << '\n'; 36 | } 37 | 38 | 39 | { 40 | // std::promise 41 | std::promise gcd_promise; 42 | std::thread worker([&] { gcd_promise.set_value(gcd(121, 22)); }); 43 | worker.detach(); 44 | // ... 45 | const int eleven = gcd_promise.get_future().get(); 46 | std::cout << eleven << '\n'; 47 | } 48 | 49 | 50 | std::cout << std::endl; 51 | } 52 | -------------------------------------------------------------------------------- /Chapter 7/04 - Mutual Exclusion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | int counter = 0; 10 | std::mutex m; 11 | std::vector threads; // Needs and . 12 | for (int t = 0; t < 4; ++t) { // Launch 4 counting threads. 13 | threads.emplace_back([&] { 14 | for (int i = 0; i < 500; ++i) { // Count to 500 in each thread. 15 | using namespace std::literals::chrono_literals; 16 | std::this_thread::sleep_for(1ms); 17 | std::scoped_lock lock(m); 18 | ++counter; 19 | } 20 | }); 21 | } 22 | for (auto& t : threads) { t.join(); } // Wait for all threads to finish. 23 | std::cout << counter << std::endl; // 2000 24 | } 25 | -------------------------------------------------------------------------------- /Chapter 7/05 - shared_lock.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/cpp17-standard-library-quick-ref/cd62302142a290a438178541c8646f39d3054143/Chapter 7/05 - shared_lock.cpp -------------------------------------------------------------------------------- /Chapter 7/06 - call_once.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void initialise(const std::string& str) 6 | { 7 | /* ... */ 8 | } 9 | 10 | int main() 11 | { 12 | { 13 | std::once_flag flag; 14 | // ... 15 | std::call_once(flag, initialise, "a string argument"); 16 | } 17 | 18 | 19 | { 20 | std::once_flag flag; 21 | // ... 22 | std::call_once(flag, [] { initialise("a string argument"); }); 23 | } 24 | 25 | 26 | std::cout << std::endl; 27 | } 28 | -------------------------------------------------------------------------------- /Chapter 7/07 - Condition Variables.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // Shared between threads: 6 | std::mutex m; 7 | std::condition_variable cv; 8 | bool ready = false; 9 | 10 | int main() 11 | { 12 | std::thread t([] { 13 | std::unique_lock lock(m); 14 | while (!ready) cv.wait(lock); 15 | // Or: 16 | // cv.wait(lock, [&]{ return ready; }); 17 | 18 | std::cout << "Finished waiting in a thread.\n"; 19 | 20 | //... access to other resources guarded by m, if any 21 | }); 22 | 23 | { // Set ready = true in the main thread: 24 | std::scoped_lock lock(m); 25 | ready = true; 26 | } 27 | cv.notify_all(); 28 | 29 | 30 | t.join(); 31 | 32 | 33 | std::cout << std::endl; 34 | } 35 | -------------------------------------------------------------------------------- /Chapter 7/08 - Cache-line Size.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Pod { 5 | int pea_1; 6 | // Possibly some other data members in between... 7 | int pea_2; 8 | }; 9 | 10 | 11 | struct KeepApart { 12 | alignas(std::hardware_destructive_interference_size) float fire; 13 | alignas(std::hardware_destructive_interference_size) int ice; 14 | }; 15 | 16 | 17 | int main() 18 | { 19 | static_assert(sizeof(Pod) <= std::hardware_constructive_interference_size); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 7/09 - Atomic Operations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | { 7 | std::atomic_int atom; // Uninitialized! 8 | } 9 | 10 | 11 | { 12 | std::atomic_int atom{ -123 }; // -123 13 | atom = 456; 14 | std::cout << atom << std::endl; // 456 15 | 16 | 17 | atom.store(123); 18 | std::cout << atom.load() << std::endl; // 123 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Chapter 7/10 - Lock-free.cpp: -------------------------------------------------------------------------------- 1 | #define _ENABLE_ATOMIC_ALIGNMENT_FIX 1 // For Visual Studio 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main() 8 | { 9 | std::atomic fundamental; 10 | std::atomic> small_type; 11 | std::atomic> large_type; 12 | std::cout << std::boolalpha // Likely results: 13 | << fundamental.is_lock_free() << '\n' // true 14 | << small_type.is_lock_free() << '\n' // true 15 | << large_type.is_lock_free() << '\n'; // false 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 7/11 - Atomic Person.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../Common/Person.h" 4 | 5 | int main() 6 | { 7 | { 8 | std::atomic person(new Person("Phil")); // non-atomic init. 9 | // ... (share references to person with other threads) 10 | person = new Person("Claire"); // atomic store 11 | person.load()->SetLastName("Dunphy"); // atomic load, non-atomic setter! 12 | } 13 | 14 | 15 | { 16 | std::atomic atomic_person(nullptr); 17 | // ... (share references to atomic_person with other threads) 18 | auto person = new Person(); 19 | person->SetFirstName("Jay"); 20 | person->SetLastName("Pritchett"); 21 | atomic_person = person; // atomic store + release fence! 22 | 23 | // ... 24 | 25 | auto p = atomic_person.exchange(nullptr); 26 | delete p; 27 | } 28 | 29 | 30 | std::cout << std::endl; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter 8/01 - assert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void foo(const char* msg) 5 | { 6 | assert(msg != nullptr); // or: assert(msg); 7 | } 8 | 9 | int main() 10 | { 11 | foo("Test"); // OK 12 | foo(nullptr); // Triggers the assertion. 13 | 14 | 15 | std::cout << std::endl; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 8/02 - Exception Pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::exception_ptr threadException; 8 | std::thread t([&threadException] { // Needs 9 | try { 10 | throw std::invalid_argument("Test"); // In worker thread 11 | } catch (...) { 12 | threadException = std::current_exception(); // Store exception 13 | } 14 | }); 15 | 16 | t.join(); // Wait for thread to finish. 17 | 18 | if (threadException) { // In main thread: handle exception if there is one. 19 | try { 20 | std::rethrow_exception(threadException); 21 | } catch (const std::exception & caughtException) { 22 | std::cout << "Caught from thread: " << caughtException.what() << '\n'; 23 | } 24 | } 25 | 26 | 27 | std::cout << std::endl; 28 | } 29 | -------------------------------------------------------------------------------- /Chapter 8/03 - Nested Exceptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void execute_helper() { 5 | throw std::range_error("Out-of-range error in execute_helper()"); 6 | } 7 | 8 | void execute() { 9 | try { 10 | execute_helper(); 11 | } catch (...) { 12 | std::throw_with_nested(std::runtime_error("Caught in execute()")); 13 | } 14 | } 15 | 16 | void print(const std::exception& exc) { 17 | std::cout << "Exception: " << exc.what() << std::endl; 18 | try { 19 | std::rethrow_if_nested(exc); 20 | } catch (const std::exception & e) { 21 | std::cout << " Nested "; 22 | print(e); 23 | } 24 | } 25 | 26 | int main() { 27 | try { 28 | execute(); 29 | } catch (const std::exception & e) { 30 | print(e); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Chapter 8/04 - system_error.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | try { 7 | throw std::system_error(std::make_error_code(std::errc::invalid_argument), 8 | "Now what am I to do with that argument?"); // optional what() message 9 | } catch (const std::exception& caughtException) { 10 | std::cout << caughtException.what(); 11 | } 12 | 13 | 14 | std::cout << std::endl; 15 | } 16 | -------------------------------------------------------------------------------- /Chapter 8/05 - cerrno.cpp: -------------------------------------------------------------------------------- 1 | #define _CRT_SECURE_NO_WARNINGS // To make this example work in Visual C++. 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include // For std::strerror 7 | 8 | int main() 9 | { 10 | errno = 0; // Reset errno to 0! 11 | auto result = std::exp(100000); // Causes an overflow error. 12 | // Convert the errno error code to an error_code instance. 13 | std::error_code errorCode(errno, std::generic_category()); 14 | std::error_condition okCondition; // Default constructor creates 15 | // a no-error condition. 16 | if (errorCode != okCondition) // Check for an error. 17 | std::cerr << "Error: " << errorCode.message() << std::endl; 18 | 19 | 20 | std::cerr << "Error: " << std::strerror(errno) << std::endl; 21 | std::perror("Error"); // Prefix string is non-optional 22 | 23 | 24 | std::cout << std::endl; 25 | } 26 | -------------------------------------------------------------------------------- /Chapter 8/06 - uncaught_exceptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Guard { 4 | const int exception_count = std::uncaught_exceptions(); 5 | public: 6 | ~Guard() { 7 | std::cout << (exception_count == std::uncaught_exceptions() 8 | ? "~Guard() invoked normally\n" 9 | : "~Guard() invoked during stack unwinding\n"); 10 | } 11 | }; 12 | 13 | 14 | int main() 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /Common/Person.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Person { 7 | public: 8 | Person() = default; 9 | explicit Person(std::string first, std::string last = "", 10 | bool isVIP = false) 11 | : m_first(move(first)), m_last(move(last)), m_isVIP(isVIP) {} 12 | 13 | const std::string& GetFirstName() const { return m_first; } 14 | void SetFirstName(std::string first) { m_first = move(first); } 15 | 16 | const std::string& GetLastName() const { return m_last; } 17 | void SetLastName(std::string last) { m_last = move(last); } 18 | 19 | bool IsVIP() const { return m_isVIP; } 20 | 21 | private: 22 | std::string m_first, m_last; 23 | bool m_isVIP = false; 24 | }; 25 | 26 | // Comparison operator 27 | bool operator<(const Person& lhs, const Person& rhs) { 28 | if (lhs.IsVIP() != rhs.IsVIP()) return rhs.IsVIP(); 29 | if (lhs.GetLastName() != rhs.GetLastName()) 30 | return lhs.GetLastName() < rhs.GetLastName(); 31 | return lhs.GetFirstName() < rhs.GetFirstName(); 32 | } 33 | 34 | // Equality operator 35 | bool operator==(const Person & lhs, const Person & rhs) { 36 | return lhs.IsVIP() == rhs.IsVIP() 37 | && lhs.GetFirstName() == rhs.GetFirstName() 38 | && lhs.GetLastName() == rhs.GetLastName(); 39 | } 40 | 41 | // Stream insertion operator for output to C++ streams. 42 | // Details of this operator can be found in Chapter 5. 43 | std::ostream& operator<<(std::ostream & os, const Person & person) { 44 | return os << person.GetFirstName() << ' ' << person.GetLastName(); 45 | } 46 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Freeware License, some rights reserved 2 | 3 | Copyright (c) 2019 Peter Van Weert and Marc Gregoire 4 | Permission is hereby granted, free of charge, to anyone obtaining a copy 5 | of this software and associated documentation files (the "Software"), 6 | to work with the Software within the limits of freeware distribution and fair use. 7 | This includes the rights to use, copy, and modify the Software for personal use. 8 | Users are also allowed and encouraged to submit corrections and modifications 9 | to the Software for the benefit of other users. 10 | 11 | It is not allowed to reuse, modify, or redistribute the Software for 12 | commercial use in any way, or for a user’s educational materials such as books 13 | or blog articles without prior permission from the copyright holder. 14 | 15 | The above copyright notice and this permission notice need to be included 16 | in all copies or substantial portions of the software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*C++17 Standard Library Quick Reference*](https://www.apress.com/9781484249222) by Peter Van Weert and Marc Gregoire (Apress, 2019). 4 | 5 | [comment]: #cover 6 | ![Cover image](9781484249222.jpg) 7 | 8 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 9 | 10 | ## Releases 11 | 12 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 13 | 14 | ## Contributions 15 | 16 | See the file Contributing.md for more information on how you can contribute to this repository. -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | # Errata for *Book Title* 2 | 3 | On **page xx** [Summary of error]: 4 | 5 | Details of error here. Highlight key pieces in **bold**. 6 | 7 | *** 8 | 9 | On **page xx** [Summary of error]: 10 | 11 | Details of error here. Highlight key pieces in **bold**. 12 | 13 | *** --------------------------------------------------------------------------------