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;
};