diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 87dd3ed..4403694 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,10 +9,11 @@ I'm not very picky about how you should contribute, but I ask that the following * Proper spelling and grammar. * If it's a language or library feature that you can write code with, please provide an example of its usage. An optimal submission would also include a short real-world use case for the feature. -* Make sure the feature is in the correct C++ version. +* Keep additions/deletions of content consistent with the cheatsheet's goals (see below). + +#### Instructions +* Make sure the feature is in the correct C++ version file (i.e. CPP11.md, etc.). * Make sure you've added the feature to the table of contents. -* Make sure you have also added the feature to the separate major C++ readme files (ie. CPP11.md, CPP14.md, etc.). -* Keep additions/deletions of content consistent with the cheatsheet's goals. ## Goals My goal for this cheatsheet is to prefer conciseness over absolute completeness. Examples of features should be minimal: if an example is overly complicated, large, or is more of an obscure usage of the feature then it will most likely be rejected in review. The reason for this goal is to teach users what the most popular uses of these features will be, and for a more thorough investigation, to learn about those from external C++ resources. diff --git a/CPP11.md b/CPP11.md index 88c3e42..0d92bc1 100644 --- a/CPP11.md +++ b/CPP11.md @@ -1,7 +1,7 @@ # C++11 ## Overview -Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words. +Many of these descriptions and examples are taken from various resources (see [Acknowledgements](#acknowledgements) section) and summarized in my own words. C++11 includes the following new language features: - [move semantics](#move-semantics) @@ -34,6 +34,8 @@ C++11 includes the following new language features: - [ref-qualified member functions](#ref-qualified-member-functions) - [trailing return types](#trailing-return-types) - [noexcept specifier](#noexcept-specifier) +- [char32_t and char16_t](#char32_t-and-char16_t) +- [raw string literals](#raw-string-literals) C++11 includes the following new library features: - [std::move](#stdmove) @@ -73,6 +75,17 @@ int x = 0; // `x` is an lvalue of type `int` int& xl = x; // `xl` is an lvalue of type `int&` int&& xr = x; // compiler error -- `x` is an lvalue int&& xr2 = 0; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0` + +void f(int& x) {} +void f(int&& x) {} + +f(x); // calls f(int&) +f(xl); // calls f(int&) +f(3); // calls f(int&&) +f(std::move(x)); // calls f(int&&) + +f(xr2); // calls f(int&) +f(std::move(xr2)); // calls f(int&& x) ``` See also: [`std::move`](#stdmove), [`std::forward`](#stdforward), [`forwarding references`](#forwarding-references). @@ -107,15 +120,15 @@ void f(T&& t) { } int x = 0; -f(0); // deduces as f(int&&) -f(x); // deduces as f(int&) +f(0); // T is int, deduces as f(int &&) => f(int&&) +f(x); // T is int&, deduces as f(int& &&) => f(int&) int& y = x; -f(y); // deduces as f(int& &&) => f(int&) +f(y); // T is int&, deduces as f(int& &&) => f(int&) int&& z = 0; // NOTE: `z` is an lvalue with type `int&&`. -f(z); // deduces as f(int&& &) => f(int&) -f(std::move(z)); // deduces as f(int&& &&) => f(int&&) +f(z); // T is int&, deduces as f(int& &&) => f(int&) +f(std::move(z)); // T is int, deduces as f(int &&) => f(int&&) ``` See also: [`std::move`](#stdmove), [`std::forward`](#stdforward), [`rvalue references`](#rvalue-references). @@ -140,7 +153,7 @@ auto sum(const First first, const Args... args) -> decltype(first) { } sum(1, 2, 3, 4, 5); // 15 -sum(1, 2, 3); // 6 +sum(1, 2, 3); // 6 sum(1.5, 2.0, 3.7); // 7.2 ``` @@ -211,7 +224,7 @@ A `lambda` is an unnamed function object capable of capturing variables in scope * `[]` - captures nothing. * `[=]` - capture local objects (local variables, parameters) in scope by value. * `[&]` - capture local objects (local variables, parameters) in scope by reference. -* `[this]` - capture `this` pointer by value. +* `[this]` - capture `this` by reference. * `[a, &b]` - capture objects `a` by value, `b` by reference. ```c++ @@ -257,7 +270,7 @@ auto add(X x, Y y) -> decltype(x + y) { add(1, 2.0); // `decltype(x + y)` => `decltype(3.0)` => `double` ``` -See also: `decltype(auto)` (C++14). +See also: [`decltype(auto) (C++14)`](README.md#decltypeauto). ### Type aliases Semantically similar to using a `typedef` however, type aliases with `using` are easier to read and are compatible with templates. @@ -299,7 +312,7 @@ Attributes provide a universal syntax over `__attribute__(...)`, `__declspec`, e ``` ### constexpr -Constant expressions are expressions evaluated by the compiler at compile-time. Only non-complex computations can be carried out in a constant expression. Use the `constexpr` specifier to indicate the variable, function, etc. is a constant expression. +Constant expressions are expressions that are *possibly* evaluated by the compiler at compile-time. Only non-complex computations can be carried out in a constant expression (these rules are progressively relaxed in later versions). Use the `constexpr` specifier to indicate the variable, function, etc. is a constant expression. ```c++ constexpr int square(int x) { return x * x; @@ -315,8 +328,9 @@ int b = square2(2); // mov edi, 2 // call square2(int) // mov DWORD PTR [rbp-8], eax ``` +In the previous snippet, notice that the computation when calling `square` is carried out at compile-time, and then the result is embedded in the code generation, while `square2` is called at run-time. -`constexpr` values are those that the compiler can evaluate at compile-time: +`constexpr` values are those that the compiler can evaluate, but are not guaranteed to, at compile-time: ```c++ const int x = 123; constexpr const int& y = x; // error -- constexpr variable `y` must be initialized by a constant expression @@ -605,23 +619,23 @@ struct Bar { }; struct Foo { - Bar getBar() & { return bar; } - Bar getBar() const& { return bar; } - Bar getBar() && { return std::move(bar); } + Bar& getBar() & { return bar; } + const Bar& getBar() const& { return bar; } + Bar&& getBar() && { return std::move(bar); } + const Bar&& getBar() const&& { return std::move(bar); } private: Bar bar; }; Foo foo{}; -Bar bar = foo.getBar(); // calls `Bar getBar() &` +Bar bar = foo.getBar(); // calls `Bar& getBar() &` const Foo foo2{}; -Bar bar2 = foo2.getBar(); // calls `Bar Foo::getBar() const&` - -Foo{}.getBar(); // calls `Bar Foo::getBar() &&` -std::move(foo).getBar(); // calls `Bar Foo::getBar() &&` +Bar bar2 = foo2.getBar(); // calls `Bar& Foo::getBar() const&` -std::move(foo2).getBar(); // calls `Bar Foo::getBar() const&&` +Foo{}.getBar(); // calls `Bar&& Foo::getBar() &&` +std::move(foo).getBar(); // calls `Bar&& Foo::getBar() &&` +std::move(foo2).getBar(); // calls `const Bar&& Foo::getBar() const&` ``` ### Trailing return types @@ -654,7 +668,7 @@ auto add(T a, U b) -> decltype(a + b) { return a + b; } ``` -In C++14, `decltype(auto)` can be used instead. +In C++14, [`decltype(auto) (C++14)`](README.md#decltypeauto) can be used instead. ### Noexcept specifier The `noexcept` specifier specifies whether a function could throw exceptions. It is an improved version of `throw()`. @@ -677,6 +691,34 @@ void g() noexcept { } ``` +### char32_t and char16_t +Provides standard types for representing UTF-8 strings. +```c++ +char32_t utf8_str[] = U"\u0123"; +char16_t utf8_str[] = u"\u0123"; +``` + +### Raw string literals +C++11 introduces a new way to declare string literals as "raw string literals". Characters issued from an escape sequence (tabs, line feeds, single backslashes, etc.) can be inputted raw while preserving formatting. This is useful, for example, to write literary text, which might contain a lot of quotes or special formatting. This can make your string literals easier to read and maintain. + +A raw string literal is declared using the following syntax: +``` +R"delimiter(raw_characters)delimiter" +``` +where: +* `delimiter` is an optional sequence of characters made of any source character except parentheses, backslashes and spaces. +* `raw_characters` is any raw character sequence; must not contain the closing sequence `")delimiter"`. + +Example: +```cpp +// msg1 and msg2 are equivalent. +const char* msg1 = "\nHello,\n\tworld!\n"; +const char* msg2 = R"( +Hello, + world! +)"; +``` + ## C++11 Library Features ### std::move @@ -738,7 +780,7 @@ void foo(bool clause) { /* do something... */ } std::vector threadsVector; threadsVector.emplace_back([]() { - // Lambda function that will be invoked + // Lambda function that will be invoked }); threadsVector.emplace_back(foo, true); // thread will run foo(true) for (auto& thread : threadsVector) { @@ -764,7 +806,7 @@ static_assert(std::is_same::type, int>::valu ### Smart pointers C++11 introduces new smart pointers: `std::unique_ptr`, `std::shared_ptr`, `std::weak_ptr`. `std::auto_ptr` now becomes deprecated and then eventually removed in C++17. -`std::unique_ptr` is a non-copyable, movable pointer that manages its own heap-allocated memory. **Note: Prefer using the `std::make_X` helper functions as opposed to using constructors. See the sections for [std::make_unique](#stdmake_unique) and [std::make_shared](#stdmake_shared).** +`std::unique_ptr` is a non-copyable, movable pointer that manages its own heap-allocated memory. **Note: Prefer using the `std::make_X` helper functions as opposed to using constructors. See the sections for [std::make_unique](https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP14.md#stdmake_unique) and [std::make_shared](#stdmake_shared).** ```c++ std::unique_ptr p1 { new Foo{} }; // `p1` owns `Foo` if (p1) { @@ -911,7 +953,7 @@ auto result = handle.get(); // wait for the result ``` ### std::begin/end -`std::begin` and `std::end` free functions were added to return begin and end iterators of a container generically. These functions also work with raw arrays which do not have begin and end member functions. +`std::begin` and `std::end` free functions were added to return begin and end iterators of a container generically. These functions also work with raw arrays which do not have `begin` and `end` member functions. ```c++ template @@ -929,7 +971,7 @@ auto b = CountTwos(arr); // 1 ## Acknowledgements * [cppreference](http://en.cppreference.com/w/cpp) - especially useful for finding examples and documentation of new library features. -* [C++ Rvalue References Explained](http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. +* [C++ Rvalue References Explained](http://web.archive.org/web/20240324121501/http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. * [clang](http://clang.llvm.org/cxx_status.html) and [gcc](https://gcc.gnu.org/projects/cxx-status.html)'s standards support pages. Also included here are the proposals for language/library features that I used to help find a description of, what it's meant to fix, and some examples. * [Compiler explorer](https://godbolt.org/) * [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended book! diff --git a/CPP14.md b/CPP14.md index db17048..f8ba613 100644 --- a/CPP14.md +++ b/CPP14.md @@ -1,7 +1,7 @@ # C++14 ## Overview -Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words. +Many of these descriptions and examples are taken from various resources (see [Acknowledgements](#acknowledgements) section) and summarized in my own words. C++14 includes the following new language features: - [binary literals](#binary-literals) @@ -122,7 +122,7 @@ static_assert(std::is_same::value == 1); static_assert(std::is_same::value == 1); ``` -See also: `decltype` (C++11). +See also: [`decltype (C++11)`](README.md#decltype). ### Relaxing constraints on constexpr functions In C++11, `constexpr` function bodies could only contain a very limited set of syntaxes, including (but not limited to): `typedef`s, `using`s, and a single `return` statement. In C++14, the set of allowable syntaxes expands greatly to include the most common syntax such as `if` statements, multiple `return`s, loops, etc. @@ -148,7 +148,7 @@ constexpr T e = T(2.7182818284590452353); ``` ### [[deprecated]] attribute -C++14 introduces the `[[deprecated]]` attribute to indicate that a unit (function, class, etc) is discouraged and likely yield compilation warnings. If a reason is provided, it will be included in the warnings. +C++14 introduces the `[[deprecated]]` attribute to indicate that a unit (function, class, etc.) is discouraged and likely yield compilation warnings. If a reason is provided, it will be included in the warnings. ```c++ [[deprecated]] void old_method(); @@ -198,11 +198,11 @@ The compiler is free to call `new T{}`, then `function_that_throws()`, and so on foo(std::make_unique(), function_that_throws(), std::make_unique()); ``` -See the C++11 section on smart pointers for more information on `std::unique_ptr` and `std::shared_ptr`. +See the section on [smart pointers (C++11)](README.md#smart-pointers) for more information on `std::unique_ptr` and `std::shared_ptr`. ## Acknowledgements * [cppreference](http://en.cppreference.com/w/cpp) - especially useful for finding examples and documentation of new library features. -* [C++ Rvalue References Explained](http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. +* [C++ Rvalue References Explained](http://web.archive.org/web/20240324121501/http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. * [clang](http://clang.llvm.org/cxx_status.html) and [gcc](https://gcc.gnu.org/projects/cxx-status.html)'s standards support pages. Also included here are the proposals for language/library features that I used to help find a description of, what it's meant to fix, and some examples. * [Compiler explorer](https://godbolt.org/) * [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended book! diff --git a/CPP17.md b/CPP17.md index fc32ec2..56b966f 100644 --- a/CPP17.md +++ b/CPP17.md @@ -1,7 +1,7 @@ # C++17 ## Overview -Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words. +Many of these descriptions and examples are taken from various resources (see [Acknowledgements](#acknowledgements) section) and summarized in my own words. C++17 includes the following new language features: - [template argument deduction for class templates](#template-argument-deduction-for-class-templates) @@ -17,7 +17,9 @@ C++17 includes the following new language features: - [constexpr if](#constexpr-if) - [utf-8 character literals](#utf-8-character-literals) - [direct-list-initialization of enums](#direct-list-initialization-of-enums) -- [fallthrough, nodiscard, maybe_unused attributes](#fallthrough-nodiscard-maybe_unused-attributes) +- [\[\[fallthrough\]\], \[\[nodiscard\]\], \[\[maybe_unused\]\] attributes](#fallthrough-nodiscard-maybe_unused-attributes) +- [\_\_has\_include](#\_\_has\_include) +- [class template argument deduction](#class-template-argument-deduction) C++17 includes the following new library features: - [std::variant](#stdvariant) @@ -30,6 +32,14 @@ C++17 includes the following new library features: - [std::byte](#stdbyte) - [splicing for maps and sets](#splicing-for-maps-and-sets) - [parallel algorithms](#parallel-algorithms) +- [std::sample](#stdsample) +- [std::clamp](#stdclamp) +- [std::reduce](#stdreduce) +- [prefix sum algorithms](#prefix-sum-algorithms) +- [gcd and lcm](#gcd-and-lcm) +- [std::not_fn](#stdnot_fn) +- [string conversion to/from numbers](#string-conversion-tofrom-numbers) +- [rounding functions for chrono durations and timepoints](#rounding-functions-for-chrono-durations-and-timepoints) ## C++17 Language Features @@ -170,14 +180,17 @@ namespace A { } } } -// vs. +``` + +The code above can be written like this: +```c++ namespace A::B::C { int i; } ``` ### Structured bindings -A proposal for de-structuring initialization, that would allow writing `auto [ x, y, z ] = expr;` where the type of `expr` was a tuple-like object, whose elements would be bound to the variables `x`, `y`, and `z` (which this construct declares). _Tuple-like objects_ include `std::tuple`, `std::pair`, `std::array`, and aggregate structures. +A proposal for de-structuring initialization, that would allow writing `auto [ x, y, z ] = expr;` where the type of `expr` was a tuple-like object, whose elements would be bound to the variables `x`, `y`, and `z` (which this construct declares). _Tuple-like objects_ include [`std::tuple`](README.md#tuples), `std::pair`, [`std::array`](README.md#stdarray), and aggregate structures. ```c++ using Coordinate = std::pair; Coordinate origin() { @@ -260,16 +273,22 @@ byte d = byte{1}; // OK byte e = byte{256}; // ERROR ``` -### fallthrough, nodiscard, maybe_unused attributes +### \[\[fallthrough\]\], \[\[nodiscard\]\], \[\[maybe_unused\]\] attributes C++17 introduces three new attributes: `[[fallthrough]]`, `[[nodiscard]]` and `[[maybe_unused]]`. -* `[[fallthrough]]` indicates to the compiler that falling through in a switch statement is intended behavior. +* `[[fallthrough]]` indicates to the compiler that falling through in a switch statement is intended behavior. This attribute may only be used in a switch statement, and must be placed before the next case/default label. ```c++ switch (n) { - case 1: [[fallthrough]] + case 1: // ... + [[fallthrough]]; case 2: // ... break; + case 3: + // ... + [[fallthrough]]; + default: + // ... } ``` @@ -306,6 +325,76 @@ void my_callback(std::string msg, [[maybe_unused]] bool error) { } ``` +### \_\_has\_include + +`__has_include (operand)` operator may be used in `#if` and `#elif` expressions to check whether a header or source file (`operand`) is available for inclusion or not. + +One use case of this would be using two libraries that work the same way, using the backup/experimental one if the preferred one is not found on the system. + +```c++ +#ifdef __has_include +# if __has_include() +# include +# define have_optional 1 +# elif __has_include() +# include +# define have_optional 1 +# define experimental_optional +# else +# define have_optional 0 +# endif +#endif +``` + +It can also be used to include headers existing under different names or locations on various platforms, without knowing which platform the program is running on, OpenGL headers are a good example for this which are located in `OpenGL\` directory on macOS and `GL\` on other platforms. + +```c++ +#ifdef __has_include +# if __has_include() +# include +# include +# elif __has_include() +# include +# include +# else +# error No suitable OpenGL headers found. +# endif +#endif +``` + +### Class template argument deduction +*Class template argument deduction* (CTAD) allows the compiler to deduce template arguments from constructor arguments. +```c++ +std::vector v{ 1, 2, 3 }; // deduces std::vector + +std::mutex mtx; +auto lck = std::lock_guard{ mtx }; // deduces to std::lock_guard + +auto p = new std::pair{ 1.0, 2.0 }; // deduces to std::pair* +``` + +For user-defined types, *deduction guides* can be used to guide the compiler how to deduce template arguments if applicable: +```c++ +template +struct container { + container(T t) {} + + template + container(Iter beg, Iter end); +}; + +// deduction guide +template +container(Iter b, Iter e) -> container::value_type>; + +container a{ 7 }; // OK: deduces container + +std::vector v{ 1.0, 2.0, 3.0 }; +auto b = container{ v.begin(), v.end() }; // OK: deduces container + +container c{ 5, 6 }; // ERROR: std::iterator_traits::value_type is not a type +``` + ## C++17 Library Features ### std::variant @@ -368,23 +457,24 @@ v; // == "trim me" ``` ### std::invoke -Invoke a `Callable` object with parameters. Examples of `Callable` objects are `std::function` or `std::bind` where an object can be called similarly to a regular function. +Invoke a `Callable` object with parameters. Examples of *callable* objects are `std::function` or lambdas; objects that can be called similarly to a regular function. ```c++ template class Proxy { - Callable c; + Callable c_; + public: - Proxy(Callable c): c(c) {} - template + Proxy(Callable c) : c_{ std::move(c) } {} + + template decltype(auto) operator()(Args&&... args) { // ... - return std::invoke(c, std::forward(args)...); + return std::invoke(c_, std::forward(args)...); } }; -auto add = [](int x, int y) { - return x + y; -}; -Proxy p {add}; + +const auto add = [](int x, int y) { return x + y; }; +Proxy p{ add }; p(1, 2); // == 3 ``` @@ -475,9 +565,142 @@ auto result1 = std::find(std::execution::par, std::begin(longVector), std::end(l auto result2 = std::sort(std::execution::seq, std::begin(longVector), std::end(longVector)); ``` +### std::sample +Samples n elements in the given sequence (without replacement) where every element has an equal chance of being selected. +```c++ +const std::string ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +std::string guid; +// Sample 5 characters from ALLOWED_CHARS. +std::sample(ALLOWED_CHARS.begin(), ALLOWED_CHARS.end(), std::back_inserter(guid), + 5, std::mt19937{ std::random_device{}() }); + +std::cout << guid; // e.g. G1fW2 +``` + +### std::clamp +Clamp given value between a lower and upper bound. +```c++ +std::clamp(42, -1, 1); // == 1 +std::clamp(-42, -1, 1); // == -1 +std::clamp(0, -1, 1); // == 0 + +// `std::clamp` also accepts a custom comparator: +std::clamp(0, -1, 1, std::less<>{}); // == 0 +``` + +### std::reduce +Fold over a given range of elements. Conceptually similar to `std::accumulate`, but `std::reduce` will perform the fold in parallel. Due to the fold being done in parallel, if you specify a binary operation, it is required to be associative and commutative. A given binary operation also should not change any element or invalidate any iterators within the given range. + +The default binary operation is std::plus with an initial value of 0. +```c++ +const std::array a{ 1, 2, 3 }; +std::reduce(std::cbegin(a), std::cend(a)); // == 6 +// Using a custom binary op: +std::reduce(std::cbegin(a), std::cend(a), 1, std::multiplies<>{}); // == 6 +``` +Additionally you can specify transformations for reducers: +```c++ +std::transform_reduce(std::cbegin(a), std::cend(a), 0, std::plus<>{}, times_ten); // == 60 + +const std::array b{ 1, 2, 3 }; +const auto product_times_ten = [](const auto a, const auto b) { return a * b * 10; }; + +std::transform_reduce(std::cbegin(a), std::cend(a), std::cbegin(b), 0, std::plus<>{}, product_times_ten); // == 140 +``` + +### Prefix sum algorithms +Support for prefix sums (both inclusive and exclusive scans) along with transformations. +```c++ +const std::array a{ 1, 2, 3 }; + +std::inclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, std::plus<>{}); // 1 3 6 + +std::exclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, 0, std::plus<>{}); // 0 1 3 + +const auto times_ten = [](const auto n) { return n * 10; }; + +std::transform_inclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, std::plus<>{}, times_ten); // 10 30 60 + +std::transform_exclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, 0, std::plus<>{}, times_ten); // 0 10 30 +``` + +### GCD and LCM +Greatest common divisor (GCD) and least common multiple (LCM). +```c++ +const int p = 9; +const int q = 3; +std::gcd(p, q); // == 3 +std::lcm(p, q); // == 9 +``` + +### std::not_fn +Utility function that returns the negation of the result of the given function. +```c++ +const std::ostream_iterator ostream_it{ std::cout, " " }; +const auto is_even = [](const auto n) { return n % 2 == 0; }; +std::vector v{ 0, 1, 2, 3, 4 }; + +// Print all even numbers. +std::copy_if(std::cbegin(v), std::cend(v), ostream_it, is_even); // 0 2 4 +// Print all odd (not even) numbers. +std::copy_if(std::cbegin(v), std::cend(v), ostream_it, std::not_fn(is_even)); // 1 3 +``` + +### String conversion to/from numbers +Convert integrals and floats to a string or vice-versa. Conversions are non-throwing, do not allocate, and are more secure than the equivalents from the C standard library. + +Users are responsible for allocating enough storage required for `std::to_chars`, or the function will fail by setting the error code object in its return value. + +These functions allow you to optionally pass a base (defaults to base-10) or a format specifier for floating type input. + +* `std::to_chars` returns a (non-const) char pointer which is one-past-the-end of the string that the function wrote to inside the given buffer, and an error code object. +* `std::from_chars` returns a const char pointer which on success is equal to the end pointer passed to the function, and an error code object. + +Both error code objects returned from these functions are equal to the default-initialized error code object on success. + +Convert the number `123` to a `std::string`: +```c++ +const int n = 123; + +// Can use any container, string, array, etc. +std::string str; +str.resize(3); // hold enough storage for each digit of `n` + +const auto [ ptr, ec ] = std::to_chars(str.data(), str.data() + str.size(), n); + +if (ec == std::errc{}) { std::cout << str << std::endl; } // 123 +else { /* handle failure */ } +``` + +Convert from a `std::string` with value `"123"` to an integer: +```c++ +const std::string str{ "123" }; +int n; + +const auto [ ptr, ec ] = std::from_chars(str.data(), str.data() + str.size(), n); + +if (ec == std::errc{}) { std::cout << n << std::endl; } // 123 +else { /* handle failure */ } +``` + +### Rounding functions for chrono durations and timepoints +Provides abs, round, ceil, and floor helper functions for `std::chrono::duration` and `std::chrono::time_point`. +```c++ +using seconds = std::chrono::seconds; +std::chrono::milliseconds d{ 5500 }; +std::chrono::abs(d); // == 5s +std::chrono::round(d); // == 6s +std::chrono::ceil(d); // == 6s +std::chrono::floor(d); // == 5s +``` + ## Acknowledgements * [cppreference](http://en.cppreference.com/w/cpp) - especially useful for finding examples and documentation of new library features. -* [C++ Rvalue References Explained](http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. +* [C++ Rvalue References Explained](http://web.archive.org/web/20240324121501/http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. * [clang](http://clang.llvm.org/cxx_status.html) and [gcc](https://gcc.gnu.org/projects/cxx-status.html)'s standards support pages. Also included here are the proposals for language/library features that I used to help find a description of, what it's meant to fix, and some examples. * [Compiler explorer](https://godbolt.org/) * [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended book! diff --git a/CPP20.md b/CPP20.md index b75d8dd..08dfabf 100644 --- a/CPP20.md +++ b/CPP20.md @@ -1,32 +1,97 @@ # C++20 ## Overview -Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words. +Many of these descriptions and examples are taken from various resources (see [Acknowledgements](#acknowledgements) section) and summarized in my own words. C++20 includes the following new language features: +- [coroutines](#coroutines) - [concepts](#concepts) +- [three-way comparison](#three-way-comparison) - [designated initializers](#designated-initializers) - [template syntax for lambdas](#template-syntax-for-lambdas) - [range-based for loop with initializer](#range-based-for-loop-with-initializer) -- [likely and unlikely attributes](#likely-and-unlikely-attributes) +- [\[\[likely\]\] and \[\[unlikely\]\] attributes](#likely-and-unlikely-attributes) - [deprecate implicit capture of this](#deprecate-implicit-capture-of-this) - [class types in non-type template parameters](#class-types-in-non-type-template-parameters) - [constexpr virtual functions](#constexpr-virtual-functions) - [explicit(bool)](#explicitbool) -- [char8_t](#char8_t) - [immediate functions](#immediate-functions) - [using enum](#using-enum) +- [lambda capture of parameter pack](#lambda-capture-of-parameter-pack) +- [char8_t](#char8_t) +- [constinit](#constinit) +- [\_\_VA\_OPT\_\_](#__VA_OPT__) C++20 includes the following new library features: - [concepts library](#concepts-library) +- [formatting library](#formatting-library) - [synchronized buffered outputstream](#synchronized-buffered-outputstream) - [std::span](#stdspan) - [bit operations](#bit-operations) - [math constants](#math-constants) - [std::is_constant_evaluated](#stdis_constant_evaluated) +- [std::make_shared supports arrays](#stdmake_shared-supports-arrays) +- [starts_with and ends_with on strings](#starts_with-and-ends_with-on-strings) +- [check if associative container has element](#check-if-associative-container-has-element) +- [std::bit_cast](#stdbit_cast) +- [std::midpoint](#stdmidpoint) +- [std::to_array](#stdto_array) +- [std::bind_front](#stdbind_front) +- [uniform container erasure](#uniform-container-erasure) +- [three-way comparison helpers](#three-way-comparison-helpers) +- [std::lexicographical_compare_three_way](#stdlexicographical_compare_three_way) ## C++20 Language Features +### Coroutines + +> **Note:** While these examples illustrate how to use coroutines at a basic level, there is lots more going on when the code is compiled. These examples are not meant to be complete coverage of C++20's coroutines. Since the `generator` and `task` classes are not provided by the standard library yet, I used the cppcoro library to compile these examples. + +_Coroutines_ are special functions that can have their execution suspended and resumed. To define a coroutine, the `co_return`, `co_await`, or `co_yield` keywords must be present in the function's body. C++20's coroutines are stackless; unless optimized out by the compiler, their state is allocated on the heap. + +An example of a coroutine is a _generator_ function, which yields (i.e. generates) a value at each invocation: +```c++ +generator range(int start, int end) { + while (start < end) { + co_yield start; + start++; + } + + // Implicit co_return at the end of this function: + // co_return; +} + +for (int n : range(0, 10)) { + std::cout << n << std::endl; +} +``` +The above `range` generator function generates values starting at `start` until `end` (exclusive), with each iteration step yielding the current value stored in `start`. The generator maintains its state across each invocation of `range` (in this case, the invocation is for each iteration in the for loop). `co_yield` takes the given expression, yields (i.e. returns) its value, and suspends the coroutine at that point. Upon resuming, execution continues after the `co_yield`. + +Another example of a coroutine is a _task_, which is an asynchronous computation that is executed when the task is awaited: +```c++ +task echo(socket s) { + for (;;) { + auto data = co_await s.async_read(); + co_await async_write(s, data); + } + + // Implicit co_return at the end of this function: + // co_return; +} +``` +In this example, the `co_await` keyword is introduced. This keyword takes an expression and suspends execution if the thing you're awaiting on (in this case, the read or write) is not ready, otherwise you continue execution. (Note that under the hood, `co_yield` uses `co_await`.) + +Using a task to lazily evaluate a value: +```c++ +task calculate_meaning_of_life() { + co_return 42; +} + +auto meaning_of_life = calculate_meaning_of_life(); +// ... +co_await meaning_of_life; // == 42 +``` + ### Concepts _Concepts_ are named compile-time predicates which constrain types. They take the following form: ``` @@ -97,7 +162,7 @@ auto g = [] () { // ... }; ``` -The `requires` keyword is used either to start a requires clause or a requires expression: +The `requires` keyword is used either to start a `requires` clause or a `requires` expression: ```c++ template requires my_concept // `requires` clause. @@ -112,7 +177,7 @@ T add(T a, T b) { return a + b; } ``` -Note that the parameter list in a requires expression is optional. Each requirement in a requires expression are one of the following: +Note that the parameter list in a `requires` expression is optional. Each requirement in a `requires` expression are one of the following: * **Simple requirements** - asserts that the given expression is valid. @@ -164,9 +229,9 @@ g(baz{}); // PASS. ```c++ template concept C = requires(T x) { - {*x} -> typename T::inner; // the type of the expression `*x` is convertible to `T::inner` + {*x} -> std::convertible_to; // the type of the expression `*x` is convertible to `T::inner` {x + 1} -> std::same_as; // the expression `x + 1` satisfies `std::same_as` - {x * 1} -> T; // the type of the expression `x * 1` is convertible to `T` + {x * 1} -> std::convertible_to; // the type of the expression `x * 1` is convertible to `T` }; ``` * **Nested requirements** - denoted by the `requires` keyword, specify additional constraints (such as those on local parameter arguments). @@ -179,6 +244,49 @@ concept C = requires(T x) { ``` See also: [concepts library](#concepts-library). +### Three-way comparison +C++20 introduces the spaceship operator (`<=>`) as a new way to write comparison functions that reduce boilerplate and help developers define clearer comparison semantics. Defining a three-way comparison operator will autogenerate the other comparison operator functions (i.e. `==`, `!=`, `<`, etc.). + +Three orderings are introduced: +* `std::strong_ordering`: The strong ordering distinguishes between items being equal (identical and interchangeable). Provides `less`, `greater`, `equivalent`, and `equal` ordering. Examples of comparisons: searching for a specific value in a list, values of integers, case-sensitive strings. +* `std::weak_ordering`: The weak ordering distinguishes between items being equivalent (not identical, but can be interchangeable for the purposes of comparison). Provides `less`, `greater`, and `equivalent` ordering. Examples of comparisons: case-insensitive strings, sorting, comparing some but not all visible members of a class. +* `std::partial_ordering`: The partial ordering follows the same principle of weak ordering but includes the case when an ordering isn't possible. Provides `less`, `greater`, `equivalent`, and `unordered` ordering. Examples of comparisons: floating-point values (e.g. `NaN`). + +A defaulted three-way comparison operator does a member-wise comparison: +```c++ +struct foo { + int a; + bool b; + char c; + + // Compare `a` first, then `b`, then `c` ... + friend auto operator<=>(const foo&) const = default; +}; + +foo f1{0, false, 'a'}, f2{0, true, 'b'}; +f1 < f2; // == true +f1 == f2; // == false +f1 >= f2; // == false +``` + +You can also define your own comparisons: +```c++ +struct foo { + int x; + bool b; + char c; + + friend std::strong_ordering operator<=>(const foo& other) const { + return x <=> other.x; + } +}; + +foo f1{0, false, 'a'}, f2{0, true, 'b'}; +f1 < f2; // == false +f1 == f2; // == true +f1 >= f2; // == true +``` + ### Designated initializers C-style designated initializer syntax. Any member fields that are not explicitly listed in the designated initializer list are default-initialized. ```c++ @@ -208,23 +316,40 @@ for (auto v = std::vector{1, 2, 3}; auto& e : v) { // prints "123" ``` -### likely and unlikely attributes -Provides a hint to the optimizer that the labelled statement is likely/unlikely to have its body executed. +### \[\[likely\]\] and \[\[unlikely\]\] attributes +Provides a hint to the optimizer that the labelled statement has a high probability of being executed. +```c++ +switch (n) { +case 1: + // ... + break; + +[[likely]] case 2: // n == 2 is considered to be arbitrarily more + // ... // likely than any other value of n + break; +} +``` + +If one of the likely/unlikely attributes appears after the right parenthesis of an if-statement, +it indicates that the branch is likely/unlikely to have its substatement (body) executed. ```c++ int random = get_random_number_between_x_and_y(0, 3); -[[likely]] if (random > 0) { +if (random > 0) [[likely]] { // body of if statement // ... } +``` -[[unlikely]] while (unlikely_truthy_condition) { +It can also be applied to the substatement (body) of an iteration statement. +```c++ +while (unlikely_truthy_condition) [[unlikely]] { // body of while statement // ... } ``` ### Deprecate implicit capture of this -Implicitly capturing `this` in a lamdba capture using `[=]` is now deprecated; prefer capturing explicitly using `[=, this]` or `[=, *this]`. +Implicitly capturing `this` in a lambda capture using `[=]` is now deprecated; prefer capturing explicitly using `[=, this]` or `[=, *this]`. ```c++ struct int_value { int n = 0; @@ -246,7 +371,7 @@ struct foo { constexpr foo(int) {} }; -template +template auto get_foo() { return f; } @@ -292,12 +417,6 @@ foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit speci foo c {"123"}; // OK ``` -### char8_t -Provides a standard type for representing UTF-8 strings. -```c++ -char8_t utf8_str[] = u8"\u0123"; -``` - ### Immediate functions Similar to `constexpr` functions, but functions with a `consteval` specifier must produce a constant. These are called `immediate functions`. ```c++ @@ -340,6 +459,52 @@ std::string_view to_string(rgba_color_channel my_channel) { } ``` +### Lambda capture of parameter pack +Capture parameter packs by value: +```c++ +template +auto f(Args&&... args){ + // BY VALUE: + return [...args = std::forward(args)] { + // ... + }; +} +``` +Capture parameter packs by reference: +```c++ +template +auto f(Args&&... args){ + // BY REFERENCE: + return [&...args = std::forward(args)] { + // ... + }; +} +``` + +### char8_t +Provides a standard type for representing UTF-8 strings. +```c++ +char8_t utf8_str[] = u8"\u0123"; +``` + +### constinit +The `constinit` specifier requires that a variable must be initialized at compile-time. +```c++ +const char* g() { return "dynamic initialization"; } +constexpr const char* f(bool p) { return p ? "constant initializer" : g(); } + +constinit const char* c = f(true); // OK +constinit const char* d = g(false); // ERROR: `g` is not constexpr, so `d` cannot be evaluated at compile-time. +``` + +### \_\_VA\_OPT\_\_ +Helps support variadic macros by evaluating to the given argument if the variadic macro is non-empty. +```c++ +#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) +F(a, b, c) // replaced by f(0, a, b, c) +F() // replaced by f(0) +``` + ## C++20 Library Features ### Concepts library @@ -369,6 +534,43 @@ Concepts are also provided by the standard library for building more complicated See also: [concepts](#concepts). +### Formatting library +Combine the simplicity of `printf` with the type-safety of `iostream`. Uses braces as placeholders, and supports custom formatting similar to printf-style specifiers. +```c++ +std::format("{1} {0}", "world", "hello"); // == "hello world" + +int x = 123; +std::string str = std::format("x: {}", x); // str == "x: 123" + +// Format to an output iterator: +for (auto x : {1, 2, 3}) { + std::format_to(std::ostream_iterator{std::cout, "\n"}, "{}", x); +} +``` + +To format custom types: +```c++ +struct fraction { + int numerator; + int denominator; +}; + +template <> +struct std::formatter +{ + constexpr auto parse(std::format_parse_context& ctx) { + return ctx.begin(); + } + + auto format(const fraction& f, std::format_context& ctx) const { + return std::format_to(ctx.out(), "{0:d}/{1:d}", f.numerator, f.denominator); + } +}; + +fraction f{1, 2}; +std::format("{}", f); // == "1/2" +``` + ### Synchronized buffered outputstream Buffers output operations for the wrapped output stream ensuring synchronization (i.e. no interleaving of output). ```c++ @@ -376,40 +578,48 @@ std::osyncstream{std::cout} << "The value of x is:" << x << std::endl; ``` ### std::span -A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. Spans can be dynamically-sized or fixed-sized. +A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. As opposed to maintaining a pointer/iterator and length field, a span wraps both of those up in a single object. + +Spans can be dynamically-sized or fixed-sized (known as their *extent*). Fixed-sized spans benefit from bounds-checking. + +Span doesn't propogate const so to construct a read-only span use `std::span`. + +Example: using a dynamically-sized span to print integers from various containers. ```c++ -void f(std::span ints) { - std::for_each(ints.begin(), ints.end(), [](auto i) { - // ... - }); +void print_ints(std::span ints) { + for (const auto n : ints) { + std::cout << n << std::endl; + } } -std::vector v = {1, 2, 3}; -f(v); -std::array a = {1, 2, 3}; -f(a); +print_ints(std::vector{ 1, 2, 3 }); +print_ints(std::array{ 1, 2, 3, 4, 5 }); + +int a[10] = { 0 }; +print_ints(a); // etc. ``` -Example: as opposed to maintaining a pointer and length field, a span wraps both of those up in a single container. + +Example: a statically-sized span will fail to compile for containers that don't match the extent of the span. ```c++ -constexpr size_t LENGTH_ELEMENTS = 3; -int* arr = new int[LENGTH_ELEMENTS]; // arr = {0, 0, 0} +void print_three_ints(std::span ints) { + for (const auto n : ints) { + std::cout << n << std::endl; + } +} -// Fixed-sized span which provides a view of `arr`. -std::span span = arr; -span[1] = 1; // arr = {0, 1, 0} +print_three_ints(std::vector{ 1, 2, 3 }); // ERROR +print_three_ints(std::array{ 1, 2, 3, 4, 5 }); // ERROR +int a[10] = { 0 }; +print_three_ints(a); // ERROR -// Dynamic-sized span which provides a view of `arr`. -std::span d_span = arr; -span[0] = 1; // arr = {1, 1, 0} -``` -```c++ -constexpr size_t LENGTH_ELEMENTS = 3; -int* arr = new int[LENGTH_ELEMENTS]; +std::array b = { 1, 2, 3 }; +print_three_ints(b); // OK -std::span span = arr; // OK -std::span span2 = arr; // ERROR -std::span span3 = arr; // ERROR +// You can construct a span manually if required: +std::vector c{ 1, 2, 3 }; +print_three_ints(std::span{ c.data(), 3 }); // OK: set pointer and length field. +print_three_ints(std::span{ c.cbegin(), c.cend() }); // OK: use iterator pairs. ``` ### Bit operations @@ -438,9 +648,103 @@ constexpr bool a = is_compile_time(); // true bool b = is_compile_time(); // false ``` +### std::make_shared supports arrays +```c++ +auto p = std::make_shared(5); // pointer to `int[5]` +// OR +auto p = std::make_shared(); // pointer to `int[5]` +``` + +### starts_with and ends_with on strings +Strings (and string views) now have the `starts_with` and `ends_with` member functions to check if a string starts or ends with the given string. +```c++ +std::string str = "foobar"; +str.starts_with("foo"); // true +str.ends_with("baz"); // false +``` + +### Check if associative container has element +Associative containers such as sets and maps have a `contains` member function, which can be used instead of the "find and check end of iterator" idiom. +```c++ +std::map map {{1, 'a'}, {2, 'b'}}; +map.contains(2); // true +map.contains(123); // false + +std::set set {1, 2, 3}; +set.contains(2); // true +``` + +### std::bit_cast +A safer way to reinterpret an object from one type to another. +```c++ +float f = 123.0; +int i = std::bit_cast(f); +``` + +### std::midpoint +Calculate the midpoint of two integers safely (without overflow). +```c++ +std::midpoint(1, 3); // == 2 +``` + +### std::to_array +Converts the given array/"array-like" object to a `std::array`. +```c++ +std::to_array("foo"); // returns `std::array` +std::to_array({1, 2, 3}); // returns `std::array` + +int a[] = {1, 2, 3}; +std::to_array(a); // returns `std::array` +``` + +### std::bind_front +Binds the first N arguments (where N is the number of arguments after the given function to `std::bind_front`) to a given free function, lambda, or member function. +```c++ +const auto f = [](int a, int b, int c) { return a + b + c; }; +const auto g = std::bind_front(f, 1, 1); +g(1); // == 3 +``` + +### Uniform container erasure +Provides `std::erase` and/or `std::erase_if` for a variety of STL containers such as string, list, vector, map, etc. + +For erasing by value use `std::erase`, or to specify a predicate when to erase elements use `std::erase_if`. Both functions return the number of erased elements. + +```c++ +std::vector v{0, 1, 0, 2, 0, 3}; +std::erase(v, 0); // v == {1, 2, 3} +std::erase_if(v, [](int n) { return n == 0; }); // v == {1, 2, 3} +``` + +### Three-way comparison helpers +Helper functions for giving names to comparison results: +```c++ +std::is_eq(0 <=> 0); // == true +std::is_lteq(0 <=> 1); // == true +std::is_gt(0 <=> 1); // == false +``` + +See also: [three-way comparison](#three-way-comparison). + +### std::lexicographical_compare_three_way +Lexicographically compares two ranges using three-way comparison and produces a result of the strongest applicable comparison category type. +```c++ +std::vector a{0, 0, 0}, b{0, 0, 0}, c{1, 1, 1}; + +auto cmp_ab = std::lexicographical_compare_three_way( + a.begin(), a.end(), b.begin(), b.end()); +std::is_eq(cmp_ab); // == true + +auto cmp_ac = std::lexicographical_compare_three_way( + a.begin(), a.end(), c.begin(), c.end()); +std::is_lt(cmp_ac); // == true +``` + +See also: [three-way comparison](#three-way-comparison), [three-way comparison helpers](#three-way-comparison-helpers). + ## Acknowledgements * [cppreference](http://en.cppreference.com/w/cpp) - especially useful for finding examples and documentation of new library features. -* [C++ Rvalue References Explained](http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. +* [C++ Rvalue References Explained](http://web.archive.org/web/20240324121501/http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. * [clang](http://clang.llvm.org/cxx_status.html) and [gcc](https://gcc.gnu.org/projects/cxx-status.html)'s standards support pages. Also included here are the proposals for language/library features that I used to help find a description of, what it's meant to fix, and some examples. * [Compiler explorer](https://godbolt.org/) * [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended book! diff --git a/LICENSE b/LICENSE index 5483565..fa52f4a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Anthony Calandra +Copyright (c) 2024 Anthony Calandra Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.md b/README.md index 230b04e..f4dfbae 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,44 @@ # C++20/17/14/11 ## Overview -Many of these descriptions and examples come from various resources (see [Acknowledgements](#acknowledgements) section), summarized in my own words. C++20 includes the following new language features: +- [coroutines](#coroutines) - [concepts](#concepts) +- [three-way comparison](#three-way-comparison) - [designated initializers](#designated-initializers) - [template syntax for lambdas](#template-syntax-for-lambdas) - [range-based for loop with initializer](#range-based-for-loop-with-initializer) -- [likely and unlikely attributes](#likely-and-unlikely-attributes) +- [\[\[likely\]\] and \[\[unlikely\]\] attributes](#likely-and-unlikely-attributes) - [deprecate implicit capture of this](#deprecate-implicit-capture-of-this) - [class types in non-type template parameters](#class-types-in-non-type-template-parameters) - [constexpr virtual functions](#constexpr-virtual-functions) - [explicit(bool)](#explicitbool) -- [char8_t](#char8_t) - [immediate functions](#immediate-functions) - [using enum](#using-enum) +- [lambda capture of parameter pack](#lambda-capture-of-parameter-pack) +- [char8_t](#char8_t) +- [constinit](#constinit) +- [\_\_VA\_OPT\_\_](#__VA_OPT__) C++20 includes the following new library features: - [concepts library](#concepts-library) +- [formatting library](#formatting-library) - [synchronized buffered outputstream](#synchronized-buffered-outputstream) - [std::span](#stdspan) - [bit operations](#bit-operations) - [math constants](#math-constants) - [std::is_constant_evaluated](#stdis_constant_evaluated) +- [std::make_shared supports arrays](#stdmake_shared-supports-arrays) +- [starts_with and ends_with on strings](#starts_with-and-ends_with-on-strings) +- [check if associative container has element](#check-if-associative-container-has-element) +- [std::bit_cast](#stdbit_cast) +- [std::midpoint](#stdmidpoint) +- [std::to_array](#stdto_array) +- [std::bind_front](#stdbind_front) +- [uniform container erasure](#uniform-container-erasure) +- [three-way comparison helpers](#three-way-comparison-helpers) +- [std::lexicographical_compare_three_way](#stdlexicographical_compare_three_way) C++17 includes the following new language features: - [template argument deduction for class templates](#template-argument-deduction-for-class-templates) @@ -39,7 +54,9 @@ C++17 includes the following new language features: - [constexpr if](#constexpr-if) - [utf-8 character literals](#utf-8-character-literals) - [direct-list-initialization of enums](#direct-list-initialization-of-enums) -- [fallthrough, nodiscard, maybe_unused attributes](#fallthrough-nodiscard-maybe_unused-attributes) +- [\[\[fallthrough\]\], \[\[nodiscard\]\], \[\[maybe_unused\]\] attributes](#fallthrough-nodiscard-maybe_unused-attributes) +- [\_\_has\_include](#\_\_has\_include) +- [class template argument deduction](#class-template-argument-deduction) C++17 includes the following new library features: - [std::variant](#stdvariant) @@ -52,6 +69,14 @@ C++17 includes the following new library features: - [std::byte](#stdbyte) - [splicing for maps and sets](#splicing-for-maps-and-sets) - [parallel algorithms](#parallel-algorithms) +- [std::sample](#stdsample) +- [std::clamp](#stdclamp) +- [std::reduce](#stdreduce) +- [prefix sum algorithms](#prefix-sum-algorithms) +- [gcd and lcm](#gcd-and-lcm) +- [std::not_fn](#stdnot_fn) +- [string conversion to/from numbers](#string-conversion-tofrom-numbers) +- [rounding functions for chrono durations and timepoints](#rounding-functions-for-chrono-durations-and-timepoints) C++14 includes the following new language features: - [binary literals](#binary-literals) @@ -99,6 +124,8 @@ C++11 includes the following new language features: - [ref-qualified member functions](#ref-qualified-member-functions) - [trailing return types](#trailing-return-types) - [noexcept specifier](#noexcept-specifier) +- [char32_t and char16_t](#char32_t-and-char16_t) +- [raw string literals](#raw-string-literals) C++11 includes the following new library features: - [std::move](#stdmove) @@ -120,6 +147,55 @@ C++11 includes the following new library features: ## C++20 Language Features +### Coroutines + +> **Note:** While these examples illustrate how to use coroutines at a basic level, there is lots more going on when the code is compiled. These examples are not meant to be complete coverage of C++20's coroutines. Since the `generator` and `task` classes are not provided by the standard library yet, I used the cppcoro library to compile these examples. + +_Coroutines_ are special functions that can have their execution suspended and resumed. To define a coroutine, the `co_return`, `co_await`, or `co_yield` keywords must be present in the function's body. C++20's coroutines are stackless; unless optimized out by the compiler, their state is allocated on the heap. + +An example of a coroutine is a _generator_ function, which yields (i.e. generates) a value at each invocation: +```c++ +generator range(int start, int end) { + while (start < end) { + co_yield start; + start++; + } + + // Implicit co_return at the end of this function: + // co_return; +} + +for (int n : range(0, 10)) { + std::cout << n << std::endl; +} +``` +The above `range` generator function generates values starting at `start` until `end` (exclusive), with each iteration step yielding the current value stored in `start`. The generator maintains its state across each invocation of `range` (in this case, the invocation is for each iteration in the for loop). `co_yield` takes the given expression, yields (i.e. returns) its value, and suspends the coroutine at that point. Upon resuming, execution continues after the `co_yield`. + +Another example of a coroutine is a _task_, which is an asynchronous computation that is executed when the task is awaited: +```c++ +task echo(socket s) { + for (;;) { + auto data = co_await s.async_read(); + co_await async_write(s, data); + } + + // Implicit co_return at the end of this function: + // co_return; +} +``` +In this example, the `co_await` keyword is introduced. This keyword takes an expression and suspends execution if the thing you're awaiting on (in this case, the read or write) is not ready, otherwise you continue execution. (Note that under the hood, `co_yield` uses `co_await`.) + +Using a task to lazily evaluate a value: +```c++ +task calculate_meaning_of_life() { + co_return 42; +} + +auto meaning_of_life = calculate_meaning_of_life(); +// ... +co_await meaning_of_life; // == 42 +``` + ### Concepts _Concepts_ are named compile-time predicates which constrain types. They take the following form: ``` @@ -190,7 +266,7 @@ auto g = [] () { // ... }; ``` -The `requires` keyword is used either to start a requires clause or a requires expression: +The `requires` keyword is used either to start a `requires` clause or a `requires` expression: ```c++ template requires my_concept // `requires` clause. @@ -205,7 +281,7 @@ T add(T a, T b) { return a + b; } ``` -Note that the parameter list in a requires expression is optional. Each requirement in a requires expression are one of the following: +Note that the parameter list in a `requires` expression is optional. Each requirement in a `requires` expression are one of the following: * **Simple requirements** - asserts that the given expression is valid. @@ -257,9 +333,9 @@ g(baz{}); // PASS. ```c++ template concept C = requires(T x) { - {*x} -> typename T::inner; // the type of the expression `*x` is convertible to `T::inner` + {*x} -> std::convertible_to; // the type of the expression `*x` is convertible to `T::inner` {x + 1} -> std::same_as; // the expression `x + 1` satisfies `std::same_as` - {x * 1} -> T; // the type of the expression `x * 1` is convertible to `T` + {x * 1} -> std::convertible_to; // the type of the expression `x * 1` is convertible to `T` }; ``` * **Nested requirements** - denoted by the `requires` keyword, specify additional constraints (such as those on local parameter arguments). @@ -272,6 +348,49 @@ concept C = requires(T x) { ``` See also: [concepts library](#concepts-library). +### Three-way comparison +C++20 introduces the spaceship operator (`<=>`) as a new way to write comparison functions that reduce boilerplate and help developers define clearer comparison semantics. Defining a three-way comparison operator will autogenerate the other comparison operator functions (i.e. `==`, `!=`, `<`, etc.). + +Three orderings are introduced: +* `std::strong_ordering`: The strong ordering distinguishes between items being equal (identical and interchangeable). Provides `less`, `greater`, `equivalent`, and `equal` ordering. Examples of comparisons: searching for a specific value in a list, values of integers, case-sensitive strings. +* `std::weak_ordering`: The weak ordering distinguishes between items being equivalent (not identical, but can be interchangeable for the purposes of comparison). Provides `less`, `greater`, and `equivalent` ordering. Examples of comparisons: case-insensitive strings, sorting, comparing some but not all visible members of a class. +* `std::partial_ordering`: The partial ordering follows the same principle of weak ordering but includes the case when an ordering isn't possible. Provides `less`, `greater`, `equivalent`, and `unordered` ordering. Examples of comparisons: floating-point values (e.g. `NaN`). + +A defaulted three-way comparison operator does a member-wise comparison: +```c++ +struct foo { + int a; + bool b; + char c; + + // Compare `a` first, then `b`, then `c` ... + friend auto operator<=>(const foo&) const = default; +}; + +foo f1{0, false, 'a'}, f2{0, true, 'b'}; +f1 < f2; // == true +f1 == f2; // == false +f1 >= f2; // == false +``` + +You can also define your own comparisons: +```c++ +struct foo { + int x; + bool b; + char c; + + friend std::strong_ordering operator<=>(const foo& other) const { + return x <=> other.x; + } +}; + +foo f1{0, false, 'a'}, f2{0, true, 'b'}; +f1 < f2; // == false +f1 == f2; // == true +f1 >= f2; // == true +``` + ### Designated initializers C-style designated initializer syntax. Any member fields that are not explicitly listed in the designated initializer list are default-initialized. ```c++ @@ -295,29 +414,46 @@ auto f = [](std::vector v) { ### Range-based for loop with initializer This feature simplifies common code patterns, helps keep scopes tight, and offers an elegant solution to a common lifetime problem. ```c++ -for (std::vector v{1, 2, 3}; auto& e : v) { +for (auto v = std::vector{1, 2, 3}; auto& e : v) { std::cout << e; } // prints "123" ``` -### likely and unlikely attributes -Provides a hint to the optimizer that the labelled statement is likely/unlikely to have its body executed. +### \[\[likely\]\] and \[\[unlikely\]\] attributes +Provides a hint to the optimizer that the labelled statement has a high probability of being executed. +```c++ +switch (n) { +case 1: + // ... + break; + +[[likely]] case 2: // n == 2 is considered to be arbitrarily more + // ... // likely than any other value of n + break; +} +``` + +If one of the likely/unlikely attributes appears after the right parenthesis of an if-statement, +it indicates that the branch is likely/unlikely to have its substatement (body) executed. ```c++ int random = get_random_number_between_x_and_y(0, 3); -[[likely]] if (random > 0) { +if (random > 0) [[likely]] { // body of if statement // ... } +``` -[[unlikely]] while (unlikely_truthy_condition) { +It can also be applied to the substatement (body) of an iteration statement. +```c++ +while (unlikely_truthy_condition) [[unlikely]] { // body of while statement // ... } ``` ### Deprecate implicit capture of this -Implicitly capturing `this` in a lamdba capture using `[=]` is now deprecated; prefer capturing explicitly using `[=, this]` or `[=, *this]`. +Implicitly capturing `this` in a lambda capture using `[=]` is now deprecated; prefer capturing explicitly using `[=, this]` or `[=, *this]`. ```c++ struct int_value { int n = 0; @@ -339,7 +475,7 @@ struct foo { constexpr foo(int) {} }; -template +template auto get_foo() { return f; } @@ -385,12 +521,6 @@ foo b = "123"; // ERROR: explicit constructor is not a candidate (explicit speci foo c {"123"}; // OK ``` -### char8_t -Provides a standard type for representing UTF-8 strings. -```c++ -char8_t utf8_str[] = u8"\u0123"; -``` - ### Immediate functions Similar to `constexpr` functions, but functions with a `consteval` specifier must produce a constant. These are called `immediate functions`. ```c++ @@ -433,6 +563,52 @@ std::string_view to_string(rgba_color_channel my_channel) { } ``` +### Lambda capture of parameter pack +Capture parameter packs by value: +```c++ +template +auto f(Args&&... args){ + // BY VALUE: + return [...args = std::forward(args)] { + // ... + }; +} +``` +Capture parameter packs by reference: +```c++ +template +auto f(Args&&... args){ + // BY REFERENCE: + return [&...args = std::forward(args)] { + // ... + }; +} +``` + +### char8_t +Provides a standard type for representing UTF-8 strings. +```c++ +char8_t utf8_str[] = u8"\u0123"; +``` + +### constinit +The `constinit` specifier requires that a variable must be initialized at compile-time. +```c++ +const char* g() { return "dynamic initialization"; } +constexpr const char* f(bool p) { return p ? "constant initializer" : g(); } + +constinit const char* c = f(true); // OK +constinit const char* d = g(false); // ERROR: `g` is not constexpr, so `d` cannot be evaluated at compile-time. +``` + +### \_\_VA\_OPT\_\_ +Helps support variadic macros by evaluating to the given argument if the variadic macro is non-empty. +```c++ +#define F(...) f(0 __VA_OPT__(,) __VA_ARGS__) +F(a, b, c) // replaced by f(0, a, b, c) +F() // replaced by f(0) +``` + ## C++20 Library Features ### Concepts library @@ -462,6 +638,43 @@ Concepts are also provided by the standard library for building more complicated See also: [concepts](#concepts). +### Formatting library +Combine the simplicity of `printf` with the type-safety of `iostream`. Uses braces as placeholders, and supports custom formatting similar to printf-style specifiers. +```c++ +std::format("{1} {0}", "world", "hello"); // == "hello world" + +int x = 123; +std::string str = std::format("x: {}", x); // str == "x: 123" + +// Format to an output iterator: +for (auto x : {1, 2, 3}) { + std::format_to(std::ostream_iterator{std::cout, "\n"}, "{}", x); +} +``` + +To format custom types: +```c++ +struct fraction { + int numerator; + int denominator; +}; + +template <> +struct std::formatter +{ + constexpr auto parse(std::format_parse_context& ctx) { + return ctx.begin(); + } + + auto format(const fraction& f, std::format_context& ctx) const { + return std::format_to(ctx.out(), "{0:d}/{1:d}", f.numerator, f.denominator); + } +}; + +fraction f{1, 2}; +std::format("{}", f); // == "1/2" +``` + ### Synchronized buffered outputstream Buffers output operations for the wrapped output stream ensuring synchronization (i.e. no interleaving of output). ```c++ @@ -469,40 +682,48 @@ std::osyncstream{std::cout} << "The value of x is:" << x << std::endl; ``` ### std::span -A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. Spans can be dynamically-sized or fixed-sized. +A span is a view (i.e. non-owning) of a container providing bounds-checked access to a contiguous group of elements. Since views do not own their elements they are cheap to construct and copy -- a simplified way to think about views is they are holding references to their data. As opposed to maintaining a pointer/iterator and length field, a span wraps both of those up in a single object. + +Spans can be dynamically-sized or fixed-sized (known as their *extent*). Fixed-sized spans benefit from bounds-checking. + +Span doesn't propogate const so to construct a read-only span use `std::span`. + +Example: using a dynamically-sized span to print integers from various containers. ```c++ -void f(std::span ints) { - std::for_each(ints.begin(), ints.end(), [](auto i) { - // ... - }); +void print_ints(std::span ints) { + for (const auto n : ints) { + std::cout << n << std::endl; + } } -std::vector v = {1, 2, 3}; -f(v); -std::array a = {1, 2, 3}; -f(a); +print_ints(std::vector{ 1, 2, 3 }); +print_ints(std::array{ 1, 2, 3, 4, 5 }); + +int a[10] = { 0 }; +print_ints(a); // etc. ``` -Example: as opposed to maintaining a pointer and length field, a span wraps both of those up in a single container. + +Example: a statically-sized span will fail to compile for containers that don't match the extent of the span. ```c++ -constexpr size_t LENGTH_ELEMENTS = 3; -int* arr = new int[LENGTH_ELEMENTS]; // arr = {0, 0, 0} +void print_three_ints(std::span ints) { + for (const auto n : ints) { + std::cout << n << std::endl; + } +} -// Fixed-sized span which provides a view of `arr`. -std::span span = arr; -span[1] = 1; // arr = {0, 1, 0} +print_three_ints(std::vector{ 1, 2, 3 }); // ERROR +print_three_ints(std::array{ 1, 2, 3, 4, 5 }); // ERROR +int a[10] = { 0 }; +print_three_ints(a); // ERROR -// Dynamic-sized span which provides a view of `arr`. -std::span d_span = arr; -span[0] = 1; // arr = {1, 1, 0} -``` -```c++ -constexpr size_t LENGTH_ELEMENTS = 3; -int* arr = new int[LENGTH_ELEMENTS]; +std::array b = { 1, 2, 3 }; +print_three_ints(b); // OK -std::span span = arr; // OK -std::span span2 = arr; // ERROR -std::span span3 = arr; // ERROR +// You can construct a span manually if required: +std::vector c{ 1, 2, 3 }; +print_three_ints(std::span{ c.data(), 3 }); // OK: set pointer and length field. +print_three_ints(std::span{ c.cbegin(), c.cend() }); // OK: use iterator pairs. ``` ### Bit operations @@ -531,6 +752,100 @@ constexpr bool a = is_compile_time(); // true bool b = is_compile_time(); // false ``` +### std::make_shared supports arrays +```c++ +auto p = std::make_shared(5); // pointer to `int[5]` +// OR +auto p = std::make_shared(); // pointer to `int[5]` +``` + +### starts_with and ends_with on strings +Strings (and string views) now have the `starts_with` and `ends_with` member functions to check if a string starts or ends with the given string. +```c++ +std::string str = "foobar"; +str.starts_with("foo"); // true +str.ends_with("baz"); // false +``` + +### Check if associative container has element +Associative containers such as sets and maps have a `contains` member function, which can be used instead of the "find and check end of iterator" idiom. +```c++ +std::map map {{1, 'a'}, {2, 'b'}}; +map.contains(2); // true +map.contains(123); // false + +std::set set {1, 2, 3}; +set.contains(2); // true +``` + +### std::bit_cast +A safer way to reinterpret an object from one type to another. +```c++ +float f = 123.0; +int i = std::bit_cast(f); +``` + +### std::midpoint +Calculate the midpoint of two integers safely (without overflow). +```c++ +std::midpoint(1, 3); // == 2 +``` + +### std::to_array +Converts the given array/"array-like" object to a `std::array`. +```c++ +std::to_array("foo"); // returns `std::array` +std::to_array({1, 2, 3}); // returns `std::array` + +int a[] = {1, 2, 3}; +std::to_array(a); // returns `std::array` +``` + +### std::bind_front +Binds the first N arguments (where N is the number of arguments after the given function to `std::bind_front`) to a given free function, lambda, or member function. +```c++ +const auto f = [](int a, int b, int c) { return a + b + c; }; +const auto g = std::bind_front(f, 1, 1); +g(1); // == 3 +``` + +### Uniform container erasure +Provides `std::erase` and/or `std::erase_if` for a variety of STL containers such as string, list, vector, map, etc. + +For erasing by value use `std::erase`, or to specify a predicate when to erase elements use `std::erase_if`. Both functions return the number of erased elements. + +```c++ +std::vector v{0, 1, 0, 2, 0, 3}; +std::erase(v, 0); // v == {1, 2, 3} +std::erase_if(v, [](int n) { return n == 0; }); // v == {1, 2, 3} +``` + +### Three-way comparison helpers +Helper functions for giving names to comparison results: +```c++ +std::is_eq(0 <=> 0); // == true +std::is_lteq(0 <=> 1); // == true +std::is_gt(0 <=> 1); // == false +``` + +See also: [three-way comparison](#three-way-comparison). + +### std::lexicographical_compare_three_way +Lexicographically compares two ranges using three-way comparison and produces a result of the strongest applicable comparison category type. +```c++ +std::vector a{0, 0, 0}, b{0, 0, 0}, c{1, 1, 1}; + +auto cmp_ab = std::lexicographical_compare_three_way( + a.begin(), a.end(), b.begin(), b.end()); +std::is_eq(cmp_ab); // == true + +auto cmp_ac = std::lexicographical_compare_three_way( + a.begin(), a.end(), c.begin(), c.end()); +std::is_lt(cmp_ac); // == true +``` + +See also: [three-way comparison](#three-way-comparison), [three-way comparison helpers](#three-way-comparison-helpers). + ## C++17 Language Features ### Template argument deduction for class templates @@ -670,7 +985,10 @@ namespace A { } } } -// vs. +``` + +The code above can be written like this: +```c++ namespace A::B::C { int i; } @@ -760,16 +1078,22 @@ byte d = byte{1}; // OK byte e = byte{256}; // ERROR ``` -### fallthrough, nodiscard, maybe_unused attributes +### \[\[fallthrough\]\], \[\[nodiscard\]\], \[\[maybe_unused\]\] attributes C++17 introduces three new attributes: `[[fallthrough]]`, `[[nodiscard]]` and `[[maybe_unused]]`. -* `[[fallthrough]]` indicates to the compiler that falling through in a switch statement is intended behavior. +* `[[fallthrough]]` indicates to the compiler that falling through in a switch statement is intended behavior. This attribute may only be used in a switch statement, and must be placed before the next case/default label. ```c++ switch (n) { - case 1: [[fallthrough]] + case 1: // ... + [[fallthrough]]; case 2: // ... break; + case 3: + // ... + [[fallthrough]]; + default: + // ... } ``` @@ -806,12 +1130,82 @@ void my_callback(std::string msg, [[maybe_unused]] bool error) { } ``` +### \_\_has\_include + +`__has_include (operand)` operator may be used in `#if` and `#elif` expressions to check whether a header or source file (`operand`) is available for inclusion or not. + +One use case of this would be using two libraries that work the same way, using the backup/experimental one if the preferred one is not found on the system. + +```c++ +#ifdef __has_include +# if __has_include() +# include +# define have_optional 1 +# elif __has_include() +# include +# define have_optional 1 +# define experimental_optional +# else +# define have_optional 0 +# endif +#endif +``` + +It can also be used to include headers existing under different names or locations on various platforms, without knowing which platform the program is running on, OpenGL headers are a good example for this which are located in `OpenGL\` directory on macOS and `GL\` on other platforms. + +```c++ +#ifdef __has_include +# if __has_include() +# include +# include +# elif __has_include() +# include +# include +# else +# error No suitable OpenGL headers found. +# endif +#endif +``` + +### Class template argument deduction +*Class template argument deduction* (CTAD) allows the compiler to deduce template arguments from constructor arguments. +```c++ +std::vector v{ 1, 2, 3 }; // deduces std::vector + +std::mutex mtx; +auto lck = std::lock_guard{ mtx }; // deduces to std::lock_guard + +auto p = new std::pair{ 1.0, 2.0 }; // deduces to std::pair* +``` + +For user-defined types, *deduction guides* can be used to guide the compiler how to deduce template arguments if applicable: +```c++ +template +struct container { + container(T t) {} + + template + container(Iter beg, Iter end); +}; + +// deduction guide +template +container(Iter b, Iter e) -> container::value_type>; + +container a{ 7 }; // OK: deduces container + +std::vector v{ 1.0, 2.0, 3.0 }; +auto b = container{ v.begin(), v.end() }; // OK: deduces container + +container c{ 5, 6 }; // ERROR: std::iterator_traits::value_type is not a type +``` + ## C++17 Library Features ### std::variant The class template `std::variant` represents a type-safe `union`. An instance of `std::variant` at any given time holds a value of one of its alternative types (it's also possible for it to be valueless). ```c++ -std::variant v {12}; +std::variant v{ 12 }; std::get(v); // == 12 std::get<0>(v); // == 12 v = 12.0; @@ -868,23 +1262,24 @@ v; // == "trim me" ``` ### std::invoke -Invoke a `Callable` object with parameters. Examples of `Callable` objects are `std::function` or `std::bind` where an object can be called similarly to a regular function. +Invoke a `Callable` object with parameters. Examples of *callable* objects are `std::function` or lambdas; objects that can be called similarly to a regular function. ```c++ template class Proxy { - Callable c; + Callable c_; + public: - Proxy(Callable c): c(c) {} - template + Proxy(Callable c) : c_{ std::move(c) } {} + + template decltype(auto) operator()(Args&&... args) { // ... - return std::invoke(c, std::forward(args)...); + return std::invoke(c_, std::forward(args)...); } }; -auto add = [](int x, int y) { - return x + y; -}; -Proxy p {add}; + +const auto add = [](int x, int y) { return x + y; }; +Proxy p{ add }; p(1, 2); // == 3 ``` @@ -975,6 +1370,139 @@ auto result1 = std::find(std::execution::par, std::begin(longVector), std::end(l auto result2 = std::sort(std::execution::seq, std::begin(longVector), std::end(longVector)); ``` +### std::sample +Samples n elements in the given sequence (without replacement) where every element has an equal chance of being selected. +```c++ +const std::string ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; +std::string guid; +// Sample 5 characters from ALLOWED_CHARS. +std::sample(ALLOWED_CHARS.begin(), ALLOWED_CHARS.end(), std::back_inserter(guid), + 5, std::mt19937{ std::random_device{}() }); + +std::cout << guid; // e.g. G1fW2 +``` + +### std::clamp +Clamp given value between a lower and upper bound. +```c++ +std::clamp(42, -1, 1); // == 1 +std::clamp(-42, -1, 1); // == -1 +std::clamp(0, -1, 1); // == 0 + +// `std::clamp` also accepts a custom comparator: +std::clamp(0, -1, 1, std::less<>{}); // == 0 +``` + +### std::reduce +Fold over a given range of elements. Conceptually similar to `std::accumulate`, but `std::reduce` will perform the fold in parallel. Due to the fold being done in parallel, if you specify a binary operation, it is required to be associative and commutative. A given binary operation also should not change any element or invalidate any iterators within the given range. + +The default binary operation is std::plus with an initial value of 0. +```c++ +const std::array a{ 1, 2, 3 }; +std::reduce(std::cbegin(a), std::cend(a)); // == 6 +// Using a custom binary op: +std::reduce(std::cbegin(a), std::cend(a), 1, std::multiplies<>{}); // == 6 +``` +Additionally you can specify transformations for reducers: +```c++ +std::transform_reduce(std::cbegin(a), std::cend(a), 0, std::plus<>{}, times_ten); // == 60 + +const std::array b{ 1, 2, 3 }; +const auto product_times_ten = [](const auto a, const auto b) { return a * b * 10; }; + +std::transform_reduce(std::cbegin(a), std::cend(a), std::cbegin(b), 0, std::plus<>{}, product_times_ten); // == 140 +``` + +### Prefix sum algorithms +Support for prefix sums (both inclusive and exclusive scans) along with transformations. +```c++ +const std::array a{ 1, 2, 3 }; + +std::inclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, std::plus<>{}); // 1 3 6 + +std::exclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, 0, std::plus<>{}); // 0 1 3 + +const auto times_ten = [](const auto n) { return n * 10; }; + +std::transform_inclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, std::plus<>{}, times_ten); // 10 30 60 + +std::transform_exclusive_scan(std::cbegin(a), std::cend(a), + std::ostream_iterator{ std::cout, " " }, 0, std::plus<>{}, times_ten); // 0 10 30 +``` + +### GCD and LCM +Greatest common divisor (GCD) and least common multiple (LCM). +```c++ +const int p = 9; +const int q = 3; +std::gcd(p, q); // == 3 +std::lcm(p, q); // == 9 +``` + +### std::not_fn +Utility function that returns the negation of the result of the given function. +```c++ +const std::ostream_iterator ostream_it{ std::cout, " " }; +const auto is_even = [](const auto n) { return n % 2 == 0; }; +std::vector v{ 0, 1, 2, 3, 4 }; + +// Print all even numbers. +std::copy_if(std::cbegin(v), std::cend(v), ostream_it, is_even); // 0 2 4 +// Print all odd (not even) numbers. +std::copy_if(std::cbegin(v), std::cend(v), ostream_it, std::not_fn(is_even)); // 1 3 +``` + +### String conversion to/from numbers +Convert integrals and floats to a string or vice-versa. Conversions are non-throwing, do not allocate, and are more secure than the equivalents from the C standard library. + +Users are responsible for allocating enough storage required for `std::to_chars`, or the function will fail by setting the error code object in its return value. + +These functions allow you to optionally pass a base (defaults to base-10) or a format specifier for floating type input. + +* `std::to_chars` returns a (non-const) char pointer which is one-past-the-end of the string that the function wrote to inside the given buffer, and an error code object. +* `std::from_chars` returns a const char pointer which on success is equal to the end pointer passed to the function, and an error code object. + +Both error code objects returned from these functions are equal to the default-initialized error code object on success. + +Convert the number `123` to a `std::string`: +```c++ +const int n = 123; + +// Can use any container, string, array, etc. +std::string str; +str.resize(3); // hold enough storage for each digit of `n` + +const auto [ ptr, ec ] = std::to_chars(str.data(), str.data() + str.size(), n); + +if (ec == std::errc{}) { std::cout << str << std::endl; } // 123 +else { /* handle failure */ } +``` + +Convert from a `std::string` with value `"123"` to an integer: +```c++ +const std::string str{ "123" }; +int n; + +const auto [ ptr, ec ] = std::from_chars(str.data(), str.data() + str.size(), n); + +if (ec == std::errc{}) { std::cout << n << std::endl; } // 123 +else { /* handle failure */ } +``` + +### Rounding functions for chrono durations and timepoints +Provides abs, round, ceil, and floor helper functions for `std::chrono::duration` and `std::chrono::time_point`. +```c++ +using seconds = std::chrono::seconds; +std::chrono::milliseconds d{ 5500 }; +std::chrono::abs(d); // == 5s +std::chrono::round(d); // == 6s +std::chrono::ceil(d); // == 6s +std::chrono::floor(d); // == 5s +``` + ## C++14 Language Features ### Binary literals @@ -1079,7 +1607,7 @@ static_assert(std::is_same::value == 1); static_assert(std::is_same::value == 1); ``` -See also: [`decltype`](#decltype). +See also: [`decltype (C++11)`](#decltype). ### Relaxing constraints on constexpr functions In C++11, `constexpr` function bodies could only contain a very limited set of syntaxes, including (but not limited to): `typedef`s, `using`s, and a single `return` statement. In C++14, the set of allowable syntaxes expands greatly to include the most common syntax such as `if` statements, multiple `return`s, loops, etc. @@ -1105,11 +1633,10 @@ constexpr T e = T(2.7182818284590452353); ``` ### [[deprecated]] attribute -C++14 introduces the `[[deprecated]]` attribute to indicate that a unit (function, class, etc) is discouraged and likely yield compilation warnings. If a reason is provided, it will be included in the warnings. +C++14 introduces the `[[deprecated]]` attribute to indicate that a unit (function, class, etc.) is discouraged and likely yield compilation warnings. If a reason is provided, it will be included in the warnings. ```c++ [[deprecated]] void old_method(); - [[deprecated("Use new_method instead")]] void legacy_method(); ``` @@ -1156,7 +1683,7 @@ The compiler is free to call `new T{}`, then `function_that_throws()`, and so on foo(std::make_unique(), function_that_throws(), std::make_unique()); ``` -See the section on [smart pointers](#smart-pointers) for more information on `std::unique_ptr` and `std::shared_ptr`. +See the section on [smart pointers (C++11)](#smart-pointers) for more information on `std::unique_ptr` and `std::shared_ptr`. ## C++11 Language Features @@ -1178,6 +1705,17 @@ int x = 0; // `x` is an lvalue of type `int` int& xl = x; // `xl` is an lvalue of type `int&` int&& xr = x; // compiler error -- `x` is an lvalue int&& xr2 = 0; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0` + +void f(int& x) {} +void f(int&& x) {} + +f(x); // calls f(int&) +f(xl); // calls f(int&) +f(3); // calls f(int&&) +f(std::move(x)); // calls f(int&&) + +f(xr2); // calls f(int&) +f(std::move(xr2)); // calls f(int&& x) ``` See also: [`std::move`](#stdmove), [`std::forward`](#stdforward), [`forwarding references`](#forwarding-references). @@ -1212,15 +1750,15 @@ void f(T&& t) { } int x = 0; -f(0); // deduces as f(int&&) -f(x); // deduces as f(int&) +f(0); // T is int, deduces as f(int &&) => f(int&&) +f(x); // T is int&, deduces as f(int& &&) => f(int&) int& y = x; -f(y); // deduces as f(int& &&) => f(int&) +f(y); // T is int&, deduces as f(int& &&) => f(int&) int&& z = 0; // NOTE: `z` is an lvalue with type `int&&`. -f(z); // deduces as f(int&& &) => f(int&) -f(std::move(z)); // deduces as f(int&& &&) => f(int&&) +f(z); // T is int&, deduces as f(int& &&) => f(int&) +f(std::move(z)); // T is int, deduces as f(int &&) => f(int&&) ``` See also: [`std::move`](#stdmove), [`std::forward`](#stdforward), [`rvalue references`](#rvalue-references). @@ -1316,7 +1854,7 @@ A `lambda` is an unnamed function object capable of capturing variables in scope * `[]` - captures nothing. * `[=]` - capture local objects (local variables, parameters) in scope by value. * `[&]` - capture local objects (local variables, parameters) in scope by reference. -* `[this]` - capture `this` pointer by value. +* `[this]` - capture `this` by reference. * `[a, &b]` - capture objects `a` by value, `b` by reference. ```c++ @@ -1362,7 +1900,7 @@ auto add(X x, Y y) -> decltype(x + y) { add(1, 2.0); // `decltype(x + y)` => `decltype(3.0)` => `double` ``` -See also: [`decltype(auto)`](#decltypeauto). +See also: [`decltype(auto) (C++14)`](#decltypeauto). ### Type aliases Semantically similar to using a `typedef` however, type aliases with `using` are easier to read and are compatible with templates. @@ -1404,7 +1942,7 @@ Attributes provide a universal syntax over `__attribute__(...)`, `__declspec`, e ``` ### constexpr -Constant expressions are expressions evaluated by the compiler at compile-time. Only non-complex computations can be carried out in a constant expression. Use the `constexpr` specifier to indicate the variable, function, etc. is a constant expression. +Constant expressions are expressions that are *possibly* evaluated by the compiler at compile-time. Only non-complex computations can be carried out in a constant expression (these rules are progressively relaxed in later versions). Use the `constexpr` specifier to indicate the variable, function, etc. is a constant expression. ```c++ constexpr int square(int x) { return x * x; @@ -1420,8 +1958,9 @@ int b = square2(2); // mov edi, 2 // call square2(int) // mov DWORD PTR [rbp-8], eax ``` +In the previous snippet, notice that the computation when calling `square` is carried out at compile-time, and then the result is embedded in the code generation, while `square2` is called at run-time. -`constexpr` values are those that the compiler can evaluate at compile-time: +`constexpr` values are those that the compiler can evaluate, but are not guaranteed to, at compile-time: ```c++ const int x = 123; constexpr const int& y = x; // error -- constexpr variable `y` must be initialized by a constant expression @@ -1710,24 +2249,23 @@ struct Bar { }; struct Foo { - Bar getBar() & { return bar; } - Bar getBar() const& { return bar; } - Bar getBar() && { return std::move(bar); } - Bar getBar() const&& { return std::move(bar); } + Bar& getBar() & { return bar; } + const Bar& getBar() const& { return bar; } + Bar&& getBar() && { return std::move(bar); } + const Bar&& getBar() const&& { return std::move(bar); } private: Bar bar; }; Foo foo{}; -Bar bar = foo.getBar(); // calls `Bar getBar() &` +Bar bar = foo.getBar(); // calls `Bar& getBar() &` const Foo foo2{}; -Bar bar2 = foo2.getBar(); // calls `Bar Foo::getBar() const&` - -Foo{}.getBar(); // calls `Bar Foo::getBar() &&` -std::move(foo).getBar(); // calls `Bar Foo::getBar() &&` +Bar bar2 = foo2.getBar(); // calls `Bar& Foo::getBar() const&` -std::move(foo2).getBar(); // calls `Bar Foo::getBar() const&&` +Foo{}.getBar(); // calls `Bar&& Foo::getBar() &&` +std::move(foo).getBar(); // calls `Bar&& Foo::getBar() &&` +std::move(foo2).getBar(); // calls `const Bar&& Foo::getBar() const&` ``` ### Trailing return types @@ -1760,7 +2298,7 @@ auto add(T a, U b) -> decltype(a + b) { return a + b; } ``` -In C++14, [decltype(auto)](#decltypeauto) can be used instead. +In C++14, [`decltype(auto) (C++14)`](#decltypeauto) can be used instead. ### Noexcept specifier The `noexcept` specifier specifies whether a function could throw exceptions. It is an improved version of `throw()`. @@ -1783,6 +2321,34 @@ void g() noexcept { } ``` +### char32_t and char16_t +Provides standard types for representing UTF-8 strings. +```c++ +char32_t utf8_str[] = U"\u0123"; +char16_t utf8_str[] = u"\u0123"; +``` + +### Raw string literals +C++11 introduces a new way to declare string literals as "raw string literals". Characters issued from an escape sequence (tabs, line feeds, single backslashes, etc.) can be inputted raw while preserving formatting. This is useful, for example, to write literary text, which might contain a lot of quotes or special formatting. This can make your string literals easier to read and maintain. + +A raw string literal is declared using the following syntax: +``` +R"delimiter(raw_characters)delimiter" +``` +where: +* `delimiter` is an optional sequence of characters made of any source character except parentheses, backslashes and spaces. +* `raw_characters` is any raw character sequence; must not contain the closing sequence `")delimiter"`. + +Example: +```cpp +// msg1 and msg2 are equivalent. +const char* msg1 = "\nHello,\n\tworld!\n"; +const char* msg2 = R"( +Hello, + world! +)"; +``` + ## C++11 Library Features ### std::move @@ -1798,7 +2364,7 @@ typename remove_reference::type&& move(T&& arg) { Transferring `std::unique_ptr`s: ```c++ -std::unique_ptr p1 {new int{0}}; // in practice, use std::make_unique +std::unique_ptr p1 {new int{0}}; // in practice, use std::make_unique std::unique_ptr p2 = p1; // error -- cannot copy unique pointers std::unique_ptr p3 = std::move(p1); // move `p1` into `p3` // now unsafe to dereference object held by `p1` @@ -1870,9 +2436,9 @@ static_assert(std::is_same::type, int>::valu ### Smart pointers C++11 introduces new smart pointers: `std::unique_ptr`, `std::shared_ptr`, `std::weak_ptr`. `std::auto_ptr` now becomes deprecated and then eventually removed in C++17. -`std::unique_ptr` is a non-copyable, movable pointer that manages its own heap-allocated memory. **Note: Prefer using the `std::make_X` helper functions as opposed to using constructors. See the sections for [std::make_unique](#stdmake_unique) and [std::make_shared](#stdmake_shared).** +`std::unique_ptr` is a non-copyable, movable pointer that manages its own heap-allocated memory. **Note: Prefer using the `std::make_X` helper functions as opposed to using constructors. See the sections for [std::make_unique](https://github.com/AnthonyCalandra/modern-cpp-features/blob/master/CPP14.md#stdmake_unique) and [std::make_shared](#stdmake_shared).** ```c++ -std::unique_ptr p1 {new Foo{}}; // `p1` owns `Foo` +std::unique_ptr p1 { new Foo{} }; // `p1` owns `Foo` if (p1) { p1->bar(); } @@ -2017,7 +2583,7 @@ auto result = handle.get(); // wait for the result ``` ### std::begin/end -`std::begin` and `std::end` free functions were added to return begin and end iterators of a container generically. These functions also work with raw arrays which do not have begin and end member functions. +`std::begin` and `std::end` free functions were added to return begin and end iterators of a container generically. These functions also work with raw arrays which do not have `begin` and `end` member functions. ```c++ template @@ -2033,16 +2599,17 @@ auto a = CountTwos(vec); // 2 auto b = CountTwos(arr); // 1 ``` + + ## Acknowledgements * [cppreference](http://en.cppreference.com/w/cpp) - especially useful for finding examples and documentation of new library features. -* [C++ Rvalue References Explained](http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. +* [C++ Rvalue References Explained](http://web.archive.org/web/20240324121501/http://thbecker.net/articles/rvalue_references/section_01.html) - a great introduction I used to understand rvalue references, perfect forwarding, and move semantics. * [clang](http://clang.llvm.org/cxx_status.html) and [gcc](https://gcc.gnu.org/projects/cxx-status.html)'s standards support pages. Also included here are the proposals for language/library features that I used to help find a description of, what it's meant to fix, and some examples. * [Compiler explorer](https://godbolt.org/) -* [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended book! +* [Scott Meyers' Effective Modern C++](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) - highly recommended series of books! * [Jason Turner's C++ Weekly](https://www.youtube.com/channel/UCxHAlbZQNFU2LgEtiqd2Maw) - nice collection of C++-related videos. * [What can I do with a moved-from object?](http://stackoverflow.com/questions/7027523/what-can-i-do-with-a-moved-from-object) * [What are some uses of decltype(auto)?](http://stackoverflow.com/questions/24109737/what-are-some-uses-of-decltypeauto) -* And many more SO posts I'm forgetting... ## Author Anthony Calandra