#include #include // 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 using Alias = T; void print(int); // -- CONCEPTS & REQUIRE EXPRESSIONS ------------------------------------------- // Simple concept from a type trait. template concept Same = std::is_same::value; // Simple requirement concepts. template 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 concept TraitTypes = requires(T t) { // T must have a type definition inner. typename T::inner; // Type alias must exist. typename Alias; }; // Compound requirement concepts. template concept TraitFns = requires(T t, const T c) { // void T::foo() must exist. { t.foo() }; // bool T::bar() const; must exist. { c.bar() } -> Same; // static void T::stat(); must exist. { T::stat() } -> Same; }; // Nested requirement concepts. template concept TraitNested = requires(T t) { // Must satisfy other concepts. requires TraitTypes; requires TraitFns; }; // -- REQUIRE EXPRESSIONS ------------------------------------------------------ // Require expressions can be evaluated to booleans. template static constexpr bool IsTraitFns = requires { requires TraitFns; }; // Require expressions can also be used in static assertions. static_assert(requires { requires Same; }); static_assert(!requires { typename Alias; requires Same; }); // -- TESTS -------------------------------------------------------------------- static_assert(requires { requires TraitAddAndPrint; }); struct FnTypeGood { using inner = int; }; struct FnTypeBad {}; static_assert(requires { requires TraitTypes; }); static_assert(!requires { requires TraitTypes; }); struct FnGood { void foo(); bool bar() const; static int stat(); }; struct FnBad {}; static_assert(requires { requires TraitFns; }); static_assert(!requires { requires TraitFns; }); struct NestedGood : FnTypeGood, FnGood {}; struct NestedBad1 : FnGood {}; struct NestedBad2 : FnTypeGood {}; static_assert(requires { requires TraitNested; }); static_assert(!requires { requires TraitNested; }); static_assert(!requires { requires TraitNested; });