Outils pour utilisateurs

Outils du site


lang:cpp:concept

Les concepts servent à forcer des classes à respecter certaines contraintes ou à définir des interfaces.

https://omnigoat.github.io/2020/01/19/cpp20-concepts/ Archive du 19/01/2020 le 05/02/2020

Définitions des concepts

  • Contrainte sur un type :
template <typename T>
concept integral = std::is_integral_v<T>;
  • Contrainte sur les fonctions :
template <typename T>
// 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<float>;
  { u.mod(f) } -> std::same_as<float>;
  // 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<const float&>;
};

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<Rectangle>);
  • Forcer un template à respecter un concept
template <class T>
requires Shape<T>
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<class T>
    void eat(T);
};

Il n'est pas possible de laisser eat template. Il faudra définir explicitement chaque surcharge.

Concepts can’t do quantifiers Archive du 10/08/2020 le 13/11/2021

Migration C++17 vers C++20

  • Code C++17
#include <tuple>
 
template <typename T>
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 <concepts>
#include <tuple>
 
template <typename T>
concept IShape = requires (T x, T z, int y)
{
   { T() } ;
   { x = z } -> std::same_as<T&>;
   { T(x) }  ;
   { x.countSides() } -> std::same_as<int>;
   { x.sideLength(y) } -> std::same_as<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 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;
};
lang/cpp/concept.txt · Dernière modification : 2021/11/13 09:04 de root