vendredi 7 août 2020

C++17- variants, visiteurs, et duck typing

Je continue à m'amuser avec les visiteurs de variants, et je trouve d'autres manières de les utiliser. En particulier, il est possible de faire du duck typing, ou typage implicite, de manière très simple et très naturelle.

C'est à dire ? Eh bien, imaginez que vous ayez des objets qui ont des méthodes et des attributs en commun. Le duck typing, c'est de considérer une interface implicite avec ces méthodes et ces attributs. Ne pas avoir à créer une interface implicite, c'est en particulier la possibilité de travailler avec des objets que l'on ne contrôle pas (bibliothèques tierces, par exemple).

Voyons ça avec un petit exemple. Nous avons 3 classes, qui ont en commun la méthode makeNoise(), et l'on veut pouvoir les mettre dans une collection et appeler cette méthode. En programmation objet classique, l'on aurait une interface Noisy, par exemple, et l'on dériverait chaque classe de cette interface. Mais disons pour le besoin de l'exercice que ce n'est pas possible. Eh bien, collons les dans un variant, puis appelons la méthode makeNoise à l'aide d'un visiteur et d'une lambda générique. Et hop, ça marche !

#include <iostream>
#include <variant>
#include <vector>

class Duck
{
public:
  void walk()
  {
    std::cout << "Walk!" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Coin !" << std::endl;
  }
};

class Cat
{
public:
  void purr()
  {
    std::cout << "Rrrron, rrron" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Miaou !" << std::endl;
  }
};

class Dog
{
public:
  void moveTail()
  {
    std::cout << "Tail moving" << std::endl;
  }
  
  void makeNoise()
  {
    std::cout << "Ouaf !" << std::endl;
  }
};

int main()
{
  using AnimalsT = std::variant<Duck, Cat, Dog>;
  
  std::vector<AnimalsT> animals({Cat(), Dog(), Cat(), Duck()});

  for(auto && animal : animals)
  {
    std::visit([](auto && arg)
               {
                 arg.makeNoise();
               },
      animal);
  }
  
  return 0;
}

Le résultat est bien évidemment:

Miaou !
Ouaf !
Miaou !
Coin !