diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-10 19:52:28 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-10 19:52:28 +0200 |
commit | 16e5ab04800f86002e9bd3f904ec60cf63238f91 (patch) | |
tree | 6ba4b3d05c11dfc1371f577889e93a2a9a9c77e3 /src/development | |
parent | 7f16e3e61379eb8d926bb35660428b6aacdd96d3 (diff) | |
download | notes-16e5ab04800f86002e9bd3f904ec60cf63238f91.tar.gz notes-16e5ab04800f86002e9bd3f904ec60cf63238f91.zip |
c++: add concept (c++20) example
Diffstat (limited to 'src/development')
-rw-r--r-- | src/development/c++.md | 7 | ||||
-rw-r--r-- | src/development/c++/Makefile | 5 | ||||
-rw-r--r-- | src/development/c++/concepts-20.cc | 105 |
3 files changed, 115 insertions, 2 deletions
diff --git a/src/development/c++.md b/src/development/c++.md index 2df60c2..1965e33 100644 --- a/src/development/c++.md +++ b/src/development/c++.md @@ -283,12 +283,17 @@ specialization for `is_valid` will be removed from the candidate set due to A more detailed description is available in the SO discussion [How does `void_t` work](https://stackoverflow.com/a/27688405). +## Example: Concepts since c++20 +```cpp +{{#include c++/concepts-20.cc:4:}} +``` + ## Template selection with partially / fully specializations. ```cpp {{#include c++/tmpl-pair.cc:3:}} ``` -# Example: Perfect forwarding +## Example: Perfect forwarding ```cpp {{#include c++/fwd-perfect.cc:3:}} ``` diff --git a/src/development/c++/Makefile b/src/development/c++/Makefile index 622bfd3..2c53e47 100644 --- a/src/development/c++/Makefile +++ b/src/development/c++/Makefile @@ -1,4 +1,4 @@ -SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc fwd-perfect.cc +SRC = concepts-11.cc concepts-20.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc fwd-perfect.cc BIN = $(SRC:.cc=) all: $(BIN) @@ -6,6 +6,9 @@ all: $(BIN) %: %.cc $(CXX) -o $* $^ -std=c++17 -g -fsanitize=address -fsanitize=undefined -fsanitize=leak +concepts-20: concepts-20.cc + $(CXX) -fsyntax-only $^ -std=c++20 + fmt: clang-format -i $(SRC) diff --git a/src/development/c++/concepts-20.cc b/src/development/c++/concepts-20.cc new file mode 100644 index 0000000..018b30b --- /dev/null +++ b/src/development/c++/concepts-20.cc @@ -0,0 +1,105 @@ +#include <concepts> +#include <type_traits> + +// REQUIRES EXPRESSION +// requires { requirement-seq } +// requires ( parameter-list ) { requirement-seq } +// +// [1] https://en.cppreference.com/w/cpp/language/requires +// [2] https://en.cppreference.com/w/cpp/language/constraints#Constraints +// +// REQUIREMENT CLAUSE +// Not the same as a REQUIREMENT EXPRESSIONS, and is used to require +// constraints (express concept bounds). +// +// [1] https://en.cppreference.com/w/cpp/language/constraints#Requires_clauses + +// -- HELPER ------------------------------------------------------------------- + +template<typename T> +using Alias = T; + +void print(int); + +// -- CONCEPTS & REQUIRE EXPRESSIONS ------------------------------------------- + +// Simple concept from a type trait. +template<typename T, typename U> +concept Same = std::is_same<T, U>::value; + +// Simple requirement concepts. +template<typename T> +concept TraitAddAndPrint = requires(T t, int i) { + // Adding T + int must be supported. + t + i; + // Calling print(T) must be available. + print(t); +}; + +// Type requirement concepts. +template<typename T> +concept TraitTypes = requires(T t) { + // T must have a type definition inner. + typename T::inner; + // Type alias must exist. + typename Alias<T>; +}; + +// Compound requirement concepts. +template<typename T> +concept TraitFns = requires(T t, const T c) { + // void T::foo() must exist. + { t.foo() }; + // bool T::bar() const; must exist. + { c.bar() } -> Same<bool>; + // static void T::stat(); must exist. + { T::stat() } -> Same<int>; +}; + +// Nested requirement concepts. +template<typename T> +concept TraitNested = requires(T t) { + // Must satisfy other concepts. + requires TraitTypes<T>; + requires TraitFns<T>; +}; + +// -- REQUIRE EXPRESSIONS ------------------------------------------------------ + +// Require expressions can be evaluated to booleans. +template<typename T> +static constexpr bool IsTraitFns = requires { requires TraitFns<T>; }; + +// Require expressions can also be used in static assertions. +static_assert(requires { requires Same<int, int>; }); +static_assert(!requires { + typename Alias<int>; + requires Same<int, void>; +}); + +// -- TESTS -------------------------------------------------------------------- + +static_assert(requires { requires TraitAddAndPrint<int>; }); + +struct FnTypeGood { + using inner = int; +}; +struct FnTypeBad {}; +static_assert(requires { requires TraitTypes<FnTypeGood>; }); +static_assert(!requires { requires TraitTypes<FnTypeBad>; }); + +struct FnGood { + void foo(); + bool bar() const; + static int stat(); +}; +struct FnBad {}; +static_assert(requires { requires TraitFns<FnGood>; }); +static_assert(!requires { requires TraitFns<FnBad>; }); + +struct NestedGood : FnTypeGood, FnGood {}; +struct NestedBad1 : FnGood {}; +struct NestedBad2 : FnTypeGood {}; +static_assert(requires { requires TraitNested<NestedGood>; }); +static_assert(!requires { requires TraitNested<NestedBad1>; }); +static_assert(!requires { requires TraitNested<NestedBad2>; }); |