91 votes

CRTP pour éviter le polymorphisme dynamique

Comment puis-je utiliser la CRTP en C++ pour éviter la surcharge des fonctions membres virtuelles ?

143voto

Dean Michael Points 2082

Il y a deux façons de procéder.

La première consiste à spécifier l'interface de manière statique pour la structure des types :

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {
  void foo(); // required to compile.
};

struct your_type : base<your_type> {
  void foo(); // required to compile.
};

La seconde consiste à éviter l'utilisation de l'idiome référence-à-base ou pointeur-à-base et à effectuer le câblage au moment de la compilation. En utilisant la définition ci-dessus, vous pouvez avoir des fonctions modèles qui ressemblent à celles-ci :

template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
  obj.foo(); // will do static dispatch
}

struct not_derived_from_base { }; // notice, not derived from base

// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload

Ainsi, la combinaison de la définition de la structure/interface et de la déduction de type au moment de la compilation dans vos fonctions vous permet d'effectuer un dispatch statique au lieu d'un dispatch dynamique. C'est l'essence même du polymorphisme statique.

18voto

fizzer Points 8193

J'ai moi-même cherché des discussions décentes sur le CRTP. L'article de Todd Veldhuizen Techniques pour le C++ scientifique est une excellente ressource pour cela (1.3) et de nombreuses autres techniques avancées comme les modèles d'expression.

J'ai également découvert que vous pouviez lire la majeure partie de l'article original de Coplien sur C++ Gems sur Google books. Peut-être que c'est toujours le cas.

1voto

Roger Lipscombe Points 34344

J'ai dû chercher CRTP . Cependant, après avoir fait cela, j'ai trouvé des informations sur Polymorphisme statique . Je soupçonne que c'est la réponse à votre question.

Il s'avère que ATL utilise ce modèle de manière assez intensive.

-5voto

user23167 Points 359

Ce site La réponse de Wikipedia contient tout ce dont vous avez besoin. A savoir :

template <class Derived> struct Base
{
    void interface()
    {
        // ...
        static_cast<Derived*>(this)->implementation();
        // ...
    }

    static void static_func()
    {
        // ...
        Derived::static_sub_func();
        // ...
    }
};

struct Derived : Base<Derived>
{
    void implementation();
    static void static_sub_func();
};

Bien que je ne sache pas combien cela vous rapporte réellement. L'overhead d'un appel de fonction virtuelle est (dépendant du compilateur, bien sûr) :

  • Mémoire : Un pointeur de fonction par fonction virtuelle
  • Durée d'exécution : Un appel de pointeur de fonction

Alors que l'overhead du polymorphisme statique CRTP est :

  • Mémoire : Duplication de la base par instanciation de modèle
  • Durée d'exécution : Un appel de pointeur de fonction + ce que fait static_cast.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X