| %module cpp20_concepts | |
| // SWIG provides only basic parser level support for C++20 concept declarations | |
| // and requires-clauses: both are silently consumed and produce no node in the | |
| // parse tree, so a constrained template wraps as if it were unconstrained. | |
| %inline %{ | |
| #include <concepts> | |
| template<typename T> | |
| concept Numeric = std::integral<T> || std::floating_point<T>; | |
| // A concept whose body refers to another concept (and uses sizeof in a | |
| // parenthesised subexpression to exercise paren tracking in the skipper). | |
| template<typename T> | |
| concept SmallNumeric = Numeric<T> && (sizeof(T) <= 4); | |
| // Function template with a trailing requires-clause. | |
| template<typename T> | |
| T cube(T x) requires Numeric<T> { | |
| return x * x * x; | |
| } | |
| // Function template with a prefix requires-clause - the constraint sits | |
| // between the template head and the return type. | |
| template<typename T> | |
| requires Numeric<T> | |
| T quad(T x) { | |
| return x * x * x * x; | |
| } | |
| // Prefix requires-clause with a compound constraint joined by '&&'. | |
| template<typename T> | |
| requires Numeric<T> && SmallNumeric<T> | |
| T half(T x) { | |
| return x / 2; | |
| } | |
| // Prefix requires-clause with a parenthesised constraint subexpression. | |
| template<typename T> | |
| requires (Numeric<T> || std::same_as<T, bool>) | |
| T identity(T x) { | |
| return x; | |
| } | |
| // Trailing requires-clause after a trailing return type, the trailing return | |
| // type being the end of the declarator. | |
| template<typename T> | |
| auto negate_value(T x) -> T requires Numeric<T> { | |
| return -x; | |
| } | |
| // Prefix and trailing requires-clauses on the same trailing return type. | |
| template<typename T> | |
| requires Numeric<T> | |
| auto triple(T x) -> T requires SmallNumeric<T> { | |
| return 3 * x; | |
| } | |
| // Trailing requires-clause whose constraint contains a requires-expression | |
| // as a primary - the inner '{ t + t; }' is part of the constraint, not the | |
| // function body. | |
| template<typename T> | |
| T add(T a, T b) requires requires (T t) { t + t; } { | |
| T result = a + b; | |
| return result; | |
| } | |
| // A concept whose body is itself a requires-expression. Functionally | |
| // equivalent to the Addable variable template in cpp20_variable_templates.i, | |
| // but spelt as a named concept usable as a constraint. | |
| template<typename T> | |
| concept Summable = requires (T t) { t + t; }; | |
| template<typename T> | |
| T sum_pair(T a, T b) requires Summable<T> { | |
| return a + b; | |
| } | |
| // A concept whose body is a requires-expression containing a compound | |
| // requirement with a trailing return type constraint - '{ a + b } -> std::same_as<T>;' | |
| template<typename T> | |
| concept AddableSame = requires(T a, T b) { | |
| { a + b } -> std::same_as<T>; | |
| }; | |
| template<typename T> | |
| T add_same(T a, T b) requires AddableSame<T> { | |
| return a + b; | |
| } | |
| // Inline 'requires requires' with a compound requirement. | |
| template<typename T> | |
| T add_inline_same(T a, T b) requires requires(T x, T y) { { x + y } -> std::same_as<T>; } { | |
| return a + b; | |
| } | |
| // Concept body with multiple simple-requirements. | |
| struct Engine { | |
| bool running = false; | |
| void start() { running = true; } | |
| void stop() { running = false; } | |
| }; | |
| template<typename T> | |
| concept Machine = requires(T m) { | |
| m.start(); | |
| m.stop(); | |
| }; | |
| template<typename T> | |
| bool cycle(T& m) requires Machine<T> { | |
| m.start(); | |
| m.stop(); | |
| return true; | |
| } | |
| // Concept body with a type-requirement, a noexcept compound-requirement and | |
| // a nested-requirement alongside a simple-requirement. | |
| struct Container { | |
| using value_type = int; | |
| void push_back(int) noexcept {} | |
| }; | |
| template<typename T> | |
| concept BasicContainer = requires(T c, typename T::value_type v) { | |
| typename T::value_type; | |
| { c.push_back(v) } noexcept; | |
| requires sizeof(T) > 0; | |
| }; | |
| template<typename T> | |
| bool check_container(T c) requires BasicContainer<T> { | |
| return true; | |
| } | |
| %} | |
| %template(cube_int) cube<int>; | |
| %template(cube_double) cube<double>; | |
| %template(quad_int) quad<int>; | |
| %template(quad_double) quad<double>; | |
| %template(half_int) half<int>; | |
| %template(identity_int) identity<int>; | |
| %template(negate_value_int) negate_value<int>; | |
| %template(triple_int) triple<int>; | |
| %template(add_int) add<int>; | |
| %template(sum_pair_int) sum_pair<int>; | |
| %template(add_same_int) add_same<int>; | |
| %template(add_inline_same_int) add_inline_same<int>; | |
| %template(cycle_engine) cycle<Engine>; | |
| %template(check_container_c) check_container<Container>; |