diff --git a/CPP20.md b/CPP20.md new file mode 100644 index 0000000..0b5582f --- /dev/null +++ b/CPP20.md @@ -0,0 +1,179 @@ +# C++20 + +## 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: +- [concepts](#concepts) + +C++20 includes the following new library features: +- [concepts library](#concepts-library) + +## C++20 Language Features + +### Concepts +_Concepts_ are named compile-time predicates which constrain template arguments. They take the following form: +``` +template < template-parameter-list > +concept concept-name = constraint-expression; +``` +where `constraint-expression` evaluates to a constexpr Boolean. Example: +```c++ +// `MyConcept` is always satisfied. +template +concept MyConcept = true; + +// Three syntactic forms for constraints (same for lambdas): +template +void f(T); + +template + requires MyConcept +void f(T); + +template +void f(T) requires MyConcept; +``` +_Constraints_ should model semantic requirements, such as whether a type is a numeric or hashable. Because constraints are evaluated at compile-time, they can provide more meaningful error messages and runtime safety. +```c++ +template +concept Integral = std::is_integral_v; +template +concept SignedIntegral = Integral && std::is_signed_v; +template +concept UnsignedIntegral = Integral && !SignedIntegral; +``` +The `requires` keyword is used either to start a requires clause or a requires expression: +```c++ +template + requires MyConcept // requires clause +void f(T); + +template +concept Callable = requires (T f) { f(); }; // requires expression + +template + requires requires (T x) { x + x; } // requires clause and expression on same line +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: + +* **Simple requirements** - asserts that the given expression is valid. + +```c++ +template +concept Callable = requires (T f) { f(); }; +``` +* **Type requirements** - denoted by the `typename` keyword followed by a type name, asserts that the given type name is valid. + +```c++ +struct Foo { + int foo; +}; + +struct Bar { + using value = int; + value data; +}; + +struct Baz { + using value = int; + value data; +}; + +// Using SFINAE, enable if `T` is a `Baz`. +template >> +struct S {}; + +template +using Ref = T&; + +template +concept C = requires { + typename T::value; // A) required nested member name + typename S; // B) required class template specialization + typename Ref; // C) required alias template substitution +}; + +template +void g(T a); + +g(Foo{}); // ERROR: Fails requirement A. +g(Bar{}); // ERROR: Fails requirement B. +g(Baz{}); // PASS. +``` +* **Compound requirements** - an expression in braces followed by a trailing return type or type constraint. + +```c++ +template +concept C = requires(T x) { + {*x} -> typename T::inner; // the expression *x must be valid + // AND the type T::inner must be valid + // AND the result of *x must be convertible to T::inner + {x + 1} -> std::Same; // the expression x + 1 must be valid + // AND std::Same must be satisfied + // i.e., (x + 1) must be a prvalue of type int + {x * 1} -> T; // the expression x * 1 must be valid + // AND its result must be convertible to T +}; +``` +* **Nested requirements** - denoted by the `requires` keyword, specify additional constraints (such as those on local parameter arguments). + +```c++ +template +concept C = requires(T x) { + requires std::Same; +}; +``` +See also: [concepts library](#concepts-library). + +## C++20 Library Features + +### Concepts library +Concepts are also provided by the standard library for building more complicated concepts. Some of these include: + +**Core language concepts:** +- `Same` - specifies two types are the same. +- `DerivedFrom` - specifies that a type is derived from another type. +- `ConvertibleTo` - specifies that a type is implicitly convertible to another type. +- `Common` - specifies that two types share a common type. +- `Integral` - specifies that a type is an integral type. +- `DefaultConstructible` - specifies that an object of a type can be default-constructed. + + **Comparison concepts:** +- `Boolean` - specifies that a type can be used in Boolean contexts. +- `EqualityComparable` - specifies that `operator==` is an equivalence relation. + + **Object concepts:** +- `Movable` - specifies that an object of a type can be moved and swapped. +- `Copyable` - specifies that an object of a type can be copied, moved, and swapped. +- `Semiregular` - specifies that an object of a type can be copied, moved, swapped, and default constructed. +- `Regular` - specifies that a type is _regular_, that is, it is both `Semiregular` and `EqualityComparable`. + + **Callable concepts:** +- `Invocable` - specifies that a callable type can be invoked with a given set of argument types. +- `Predicate` - specifies that a callable type is a Boolean predicate. + +See also: [concepts](#concepts). + +## 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. +* [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! +* [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 + +## Content Contributors +See: https://github.com/AnthonyCalandra/modern-cpp-features/graphs/contributors + +## License +MIT diff --git a/README.md b/README.md index f4781eb..c6bf2ad 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ -# C++17/14/11 +# 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. -Also, there are now dedicated readme pages for each major C++ version. +C++20 includes the following new language features: +- [concepts](#concepts) + +C++20 includes the following new library features: +- [concepts library](#concepts-library) C++17 includes the following new language features: - [template argument deduction for class templates](#template-argument-deduction-for-class-templates) @@ -92,6 +96,155 @@ C++11 includes the following new library features: - [memory model](#memory-model) - [std::async](#stdasync) +## C++20 Language Features + +### Concepts +_Concepts_ are named compile-time predicates which constrain template arguments. They take the following form: +``` +template < template-parameter-list > +concept concept-name = constraint-expression; +``` +where `constraint-expression` evaluates to a constexpr Boolean. Example: +```c++ +// `MyConcept` is always satisfied. +template +concept MyConcept = true; + +// Three syntactic forms for constraints (same for lambdas): +template +void f(T); + +template + requires MyConcept +void f(T); + +template +void f(T) requires MyConcept; +``` +_Constraints_ should model semantic requirements, such as whether a type is a numeric or hashable. Because constraints are evaluated at compile-time, they can provide more meaningful error messages and runtime safety. +```c++ +template +concept Integral = std::is_integral_v; +template +concept SignedIntegral = Integral && std::is_signed_v; +template +concept UnsignedIntegral = Integral && !SignedIntegral; +``` +The `requires` keyword is used either to start a requires clause or a requires expression: +```c++ +template + requires MyConcept // requires clause +void f(T); + +template +concept Callable = requires (T f) { f(); }; // requires expression + +template + requires requires (T x) { x + x; } // requires clause and expression on same line +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: + +* **Simple requirements** - asserts that the given expression is valid. + +```c++ +template +concept Callable = requires (T f) { f(); }; +``` +* **Type requirements** - denoted by the `typename` keyword followed by a type name, asserts that the given type name is valid. + +```c++ +struct Foo { + int foo; +}; + +struct Bar { + using value = int; + value data; +}; + +struct Baz { + using value = int; + value data; +}; + +// Using SFINAE, enable if `T` is a `Baz`. +template >> +struct S {}; + +template +using Ref = T&; + +template +concept C = requires { + typename T::value; // A) required nested member name + typename S; // B) required class template specialization + typename Ref; // C) required alias template substitution +}; + +template +void g(T a); + +g(Foo{}); // ERROR: Fails requirement A. +g(Bar{}); // ERROR: Fails requirement B. +g(Baz{}); // PASS. +``` +* **Compound requirements** - an expression in braces followed by a trailing return type or type constraint. + +```c++ +template +concept C = requires(T x) { + {*x} -> typename T::inner; // the expression *x must be valid + // AND the type T::inner must be valid + // AND the result of *x must be convertible to T::inner + {x + 1} -> std::Same; // the expression x + 1 must be valid + // AND std::Same must be satisfied + // i.e., (x + 1) must be a prvalue of type int + {x * 1} -> T; // the expression x * 1 must be valid + // AND its result must be convertible to T +}; +``` +* **Nested requirements** - denoted by the `requires` keyword, specify additional constraints (such as those on local parameter arguments). + +```c++ +template +concept C = requires(T x) { + requires std::Same; +}; +``` +See also: [concepts library](#concepts-library). + +## C++20 Library Features + +### Concepts library +Concepts are also provided by the standard library for building more complicated concepts. Some of these include: + +**Core language concepts:** +- `Same` - specifies two types are the same. +- `DerivedFrom` - specifies that a type is derived from another type. +- `ConvertibleTo` - specifies that a type is implicitly convertible to another type. +- `Common` - specifies that two types share a common type. +- `Integral` - specifies that a type is an integral type. +- `DefaultConstructible` - specifies that an object of a type can be default-constructed. + + **Comparison concepts:** +- `Boolean` - specifies that a type can be used in Boolean contexts. +- `EqualityComparable` - specifies that `operator==` is an equivalence relation. + + **Object concepts:** +- `Movable` - specifies that an object of a type can be moved and swapped. +- `Copyable` - specifies that an object of a type can be copied, moved, and swapped. +- `Semiregular` - specifies that an object of a type can be copied, moved, swapped, and default constructed. +- `Regular` - specifies that a type is _regular_, that is, it is both `Semiregular` and `EqualityComparable`. + + **Callable concepts:** +- `Invocable` - specifies that a callable type can be invoked with a given set of argument types. +- `Predicate` - specifies that a callable type is a Boolean predicate. + +See also: [concepts](#concepts). + ## C++17 Language Features ### Template argument deduction for class templates