/
niceSOFT
/
swig
Обзор
Документация
Войти
/
niceSOFT
/
swig
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Examples/test-suite/cpp20_concepts_classes.i
142 строки
5 KB
William S Fulton
C++20 concepts: extend tests and document broader support
13 май 2026, 01:04
13 май 2026, 01:04
ad7b85e
Код
Авторство
О чём код?
%module cpp20_concepts_classes // C++20 concepts applied to class templates: prefix requires-clause, trailing requires on ordinary methods, compound '&&', constrained constructor. %inline %{ #include <concepts> template<typename T> concept Numeric = std::integral<T> || std::floating_point<T>; template<typename T> concept SmallNumeric = Numeric<T> && (sizeof(T) <= 4); // Class template with a prefix requires-clause on the template head. template<typename T> requires Numeric<T> class NumericBox { T value; public: NumericBox() : value(T()) {} NumericBox(T v) : value(v) {} T get() const { return value; } void set(T v) { value = v; } T cube() const { return value * value * value; } }; // Unconstrained class template whose ordinary methods carry their own trailing requires-clauses referencing the class's template parameter. template<typename T> class Holder { T value; public: Holder() : value(T()) {} Holder(T v) : value(v) {} T get() const { return value; } void set(T v) { value = v; } // Trailing requires-clause on an ordinary method. T doubled() const requires Numeric<T> { return value + value; } }; // Class template with a compound prefix requires-clause joined by '&&'. template<typename T> requires Numeric<T> && SmallNumeric<T> class SmallBox { T value; public: SmallBox() : value(T()) {} SmallBox(T v) : value(v) {} T get() const { return value; } }; // Class template with a constrained constructor (the class is otherwise unconstrained, but only // Numeric T values can construct from a value). The constructor's trailing requires-clause is held // on the constructor node's "constraint" attribute and is substituted when the class template is // instantiated; both 'int' and 'double' satisfy 'Numeric<T>' so both instantiations succeed. template<typename T> class CheckedBox { T value; public: CheckedBox() : value(T()) {} CheckedBox(T v) requires Numeric<T> : value(v) {} T get() const { return value; } }; // Out of line definition of a member function template of a class template, // with a prefix requires-clause on its own template head. Exercises the // requires_clause_opt path on a doubly templated declaration. template<typename T> class OutOfLineBox { T value; public: OutOfLineBox(T v) : value(v) {} T get() const { return value; } template<typename U> requires Numeric<U> T scaled(U factor) const; }; template<typename T> template<typename U> requires Numeric<U> T OutOfLineBox<T>::scaled(U factor) const { return value * (T)factor; } // Primary class template plus a structural partial specialization (T -> T*) whose template head additionally carries // a requires-clause. SWIG's partial spec matcher selects on the structural pattern alone; the requires-clause is // captured but not evaluated. The two specs wrap as distinct types with their own method sets - primary_method only // reaches Storage<int>, partial_method only reaches Storage<int*>. // // Limitation: SWIG does not select between candidates whose structural template-argument patterns are identical and // which differ only by a requires-clause, e.g. // // template<typename T> struct S { ... }; // primary // template<typename T> requires Numeric<T> struct S<T> { ... }; // concept only "partial spec" // // SWIG sees both as 'S<T>' and the last declared candidate wins for every instantiation; C++20 constraint // subsumption is not modelled. Use a structural pattern to differentiate (T vs T*, T const&, etc.) when partial // specs need to be wrapped distinctly. template<typename T> struct Storage { int kind() const { return 1; } int primary_method() const { return 100; } }; template<typename T> requires Numeric<T> struct Storage<T*> { int kind() const { return 2; } int partial_method() const { return 200; } }; // Concept constrained CRTP - the base class is the constrained template parameter, so the prefix // requires-clause sits between the template head and a base list that names that parameter. Verifies // the constraint does not interfere with the inheritance / base list path. template<typename T> concept HasDraw = requires(T t) { t.draw(); }; struct Drawable { int counter = 0; void draw() { ++counter; } }; template<typename Derived> requires HasDraw<Derived> class View : public Derived { public: void render() { this->draw(); this->draw(); } }; %} %template(NumericBoxInt) NumericBox<int>; %template(NumericBoxDouble) NumericBox<double>; %template(HolderInt) Holder<int>; %template(HolderDouble) Holder<double>; %template(SmallBoxInt) SmallBox<int>; %template(CheckedBoxInt) CheckedBox<int>; %template(CheckedBoxDouble) CheckedBox<double>; %template(OutOfLineBoxInt) OutOfLineBox<int>; %template(StorageInt) Storage<int>; %template(StorageIntPtr) Storage<int*>; %template(ViewDrawable) View<Drawable>;