Les concepts servent à forcer des classes à respecter certaines contraintes ou à définir des interfaces. [[https://omnigoat.github.io/2020/01/19/cpp20-concepts/|https://omnigoat.github.io/2020/01/19/cpp20-concepts/]] {{ :lang:cpp:concept:omni_blogs_2020-02-05_21_56_31_.html |Archive du 19/01/2020 le 05/02/2020}} ====Définitions des concepts==== * Contrainte sur un type : template concept integral = std::is_integral_v; * Contrainte sur les fonctions : template // Le type est cv. Donc, il faut utiliser deux paramètres, l'un pour const, l'autre sans. concept Shape = requires(const T t, T u, float f) { // Le type de retour est facultatif mais conseillé. { t.area() } -> std::same_as; { u.mod(f) } -> std::same_as; // On impose une variable. // Elle peut être static / constexpr ou non. // Il faut la déclarer comme une référence. { t.varr } -> std::same_as; }; ====Application des concepts==== * Vérification qu'une structure respecte un concept struct Rectangle { consteval float area() const {return 1.;} consteval float mod(float f) {return f;} static constexpr float varr = 2.f; }; static_assert(Shape); * Forcer un template à respecter un concept template requires Shape class AllFormes { }; * Cast d'un type vers un concept int main() { Rectangle a; Shape auto &b = a; b.mod(); } * Déclaration d'une fonction dont un des paramètres doit respecter un concept void foo(const Concept auto&) {} Et cela va générer un symbole pour chaque type. ====Restriction==== ===Fonction template=== Il n'est pas possible de définir un concept avec un template non défini dans le concept. Exemple: struct Goat { template void eat(T); }; Il n'est pas possible de laisser ''eat'' template. Il faudra définir explicitement chaque surcharge. [[https://quuxplusone.github.io/blog/2020/08/10/concepts-cant-do-quantifiers/|Concepts can’t do quantifiers]] {{ :lang:cpp:concept:concepts_can_t_do_quantifiers_arthur_o_dwyer_stuff_mostly_about_c_2021-11-13_09_03_00_.html |Archive du 10/08/2020 le 13/11/2021}} ====Migration C++17 vers C++20==== * Code C++17 #include template concept bool IShape = requires (T x, T z, int y) { { T() } ; { x = z } -> T&; { T(x) } ; { x.countSides() } -> int; { x.sideLength(y) } -> int; }; struct Rectangle { Rectangle() {}; Rectangle(const Rectangle& other) {}; Rectangle& operator=(Rectangle& other) {return *this; }; const char * getName() { return "Rectangle"; } int countSides() {return 4;} int sideLength(int side) { return (side % 2 == 0) ? 10 : 5; } }; struct Square { Square() {}; Square(const Square& other) {}; Square& operator=(Square& other) {return *this; }; const char * getName() { return "Square"; } int countSides() {return 4;} int sideLength(int side) { return 10; } }; void print(IShape& shape) { for (int side = 0 ; side < shape.countSides() ; ++side ) { //std::cout << shape.getName() << " side=" << shape.sideLength(side) << "\n"; } }; int main() { Square square; Rectangle rect; auto shapes = std::make_tuple(square, rect); std::apply([](auto&... shape) { ((print(shape)), ...); }, shapes) ; return 0; }; * Code C++20 #include #include template concept IShape = requires (T x, T z, int y) { { T() } ; { x = z } -> std::same_as; { T(x) } ; { x.countSides() } -> std::same_as; { x.sideLength(y) } -> std::same_as; }; struct Rectangle { Rectangle() {}; Rectangle(const Rectangle& other) {}; Rectangle& operator=(Rectangle& other) {return *this; }; const char * getName() { return "Rectangle"; } int countSides() {return 4;} int sideLength(int side) { return (side % 2 == 0) ? 10 : 5; } }; struct Square { Square() {}; Square(const Square& other) {}; Square& operator=(Square& other) {return *this; }; const char * getName() { return "Square"; } int countSides() {return 4;} int sideLength(int side) { return 10; } }; void print(IShape auto& shape) { for (int side = 0 ; side < shape.countSides() ; ++side ) { //std::cout << shape.getName() << " side=" << shape.sideLength(side) << "\n"; } }; int main() { Square square; Rectangle rect; auto shapes = std::make_tuple(square, rect); std::apply([](auto&... shape) { ((print(shape)), ...); }, shapes) ; return 0; };