aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2024-04-10 19:52:28 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2024-04-10 19:52:28 +0200
commit16e5ab04800f86002e9bd3f904ec60cf63238f91 (patch)
tree6ba4b3d05c11dfc1371f577889e93a2a9a9c77e3
parent7f16e3e61379eb8d926bb35660428b6aacdd96d3 (diff)
downloadnotes-16e5ab04800f86002e9bd3f904ec60cf63238f91.tar.gz
notes-16e5ab04800f86002e9bd3f904ec60cf63238f91.zip
c++: add concept (c++20) example
-rw-r--r--src/development/c++.md7
-rw-r--r--src/development/c++/Makefile5
-rw-r--r--src/development/c++/concepts-20.cc105
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>; });