2010-04-25 7 views
1

Voilà ce que je voudrais faire en utilisant des modèles:C++, programmation générique et fonctions virtuelles. Comment puis-je obtenir ce que je veux?

struct op1 
{ 
    virtual void Method1() = 0; 
} 

... 

struct opN 
{ 
    virtual void MethodN() = 0; 
} 

struct test : op1, op2, op3, op4 
{ 
    virtual void Method1(){/*do work1*/}; 
    virtual void Method2(){/*do work2*/}; 
    virtual void Method3(){/*do work3*/}; 
    virtual void Method4(){/*do work4*/}; 
} 

Je voudrais avoir une classe qui dérive tout simplement d'une classe de modèle qui fournit ces déclarations de méthode tout en même temps en les rendant virtuel. Voilà ce que j'ai réussi à trouver:

#include <iostream> 

template< size_t N > 
struct ops : ops< N - 1 > 
{ 
protected: 
    virtual void DoStuff(){ std::cout<<N<<std::endl; }; 
public: 
    template< size_t i > 
    void Method() 
    { if(i < N) ops<i>::DoStuff(); } 
    //leaving out compile time asserts for brevity 
}; 

template<> 
struct ops<0> 
{ 
}; 

struct test : ops<6> 
{ 
}; 

int main(int argc, char ** argv) 
{ 
    test obj; 
    obj.Method<3>(); //prints 3 
    return 0; 
} 

Cependant, comme vous l'avez probablement deviné, je suis incapable de passer outre l'une des 6 méthodes que j'ai hérité. Il me manque évidemment quelque chose ici. Quelle est mon erreur? Non, ce n'est pas un devoir. C'est de la curiosité.

+0

Est-ce que même compilez? Je pense que le compilateur se lancerait dans une boucle infinie en essayant d'instancier 'ops '... – tzaman

+0

Il ne le serait pas s'il y avait une spécialisation pour' ops <1> 'ou' ops <0> 'qui le termine. –

+0

Je pense que le problème est que vous n'avez pas hérité de 6 méthodes - vous avez défini une méthode dans la classe de base et ensuite réimplémenté la même méthode 5 fois dans les descendants. –

Répondre

3

Testé avec GCC 4.3. Ne sais même pas pourquoi j'ai passé du temps à ce sujet: -/

#include <iostream> 

template <std::size_t N> 
struct mark 
{ }; 

template <std::size_t N> 
struct op : op <N - 1> 
{ 
    virtual void do_method (const mark <N>&) = 0; 
}; 

template <> 
struct op <1> 
{ 
    virtual void do_method (const mark <1>&) = 0; 
}; 

struct test : op <2> 
{ 
    template <std::size_t K> 
    void 
    method() 
    { do_method (mark <K>()); } 

    virtual void do_method (const mark <1>&) 
    { std::cout << "1\n"; } 

    virtual void do_method (const mark <2>&) 
    { std::cout << "2\n"; } 
}; 

int 
main() 
{ 
    test x; 

    x.method <1>(); 
    x.method <2>(); 
} 

Je ne sais pas comment déplacer le « prettifier » fonction method() modèle de test.

+1

Vous pouvez utiliser un 'template op' pour les méthodes et terminer avec une spécialisation vide' template <> struct op <0> {}; '. –

+0

@gf: Bon point. – doublep

+0

Merci. Je savais que la réponse avait quelque chose à voir avec la conversion d'un int en un type et en l'utilisant pour différencier les fonctions appelées. – Carl

1
template< size_t N > 
struct ops : ops< N - 1 > 

Ceci code une boucle sans fin. La récursion ne s'arrête pas lorsque N atteint 0. Ajoutez une spécialisation dans le cas final, immédiatement après le modèle principal:

template<> 
struct ops<0> {} 

Aussi, qu'est-ce que cela fait? Pourquoi ne pas simplement appeler directement le ops<i>::DoStuff()?

template< size_t i > 
void Method() 
{ if(i < N) ops<i>::DoStuff(); } 
+0

C'est une version d'exécution de boost :: enable_if. Si je suis trop gros, la méthode ne fait rien. –

+0

Donc, nous prenons un modèle qui pourrait faire n'importe quoi, et ajouter la possibilité qu'il pourrait tranquillement ne rien faire si l'argument est hors de portée. Amusement. – Potatoswatter

+0

True. Cela fait. J'aurais dû ajouter dans la spécialisation pour terminer la hiérarchie. MISE À JOUR: Juste fait. – Carl

1

Pour mimer votre désir d'origine:

#define MAKE_OPS(N) template<> struct Ops<N> : Ops<N-1> { virtual void Method##N() = 0; } 

template<int N> 
struct Ops; 

template<> 
struct Ops<0> { }; 

MAKE_OPS(1); 
MAKE_OPS(2); 
template<> struct Ops<3> : Ops<2> { virtual void Method3() { std::cout << "3" << std::endl; } }; 
MAKE_OPS(4); 
MAKE_OPS(5); 
MAKE_OPS(6); 

struct Test : Ops<3> { 
    virtual void Method1() { std::cout << 1 << std::endl; } 
    virtual void Method2() { std::cout << 2 << std::endl; } 
}; 
+0

Oui, cela fonctionnerait, mais tout le problème est que je ne veux pas avoir à écrire une nouvelle déclaration de méthode pour chaque méthode supplémentaire. Appelez-moi paresseux, mais pour moi, c'est exactement le genre de choses qui devrait pouvoir être généré automatiquement, ce qui est la raison de cet exercice. – Carl

+0

@carleeto: Je sais que ce n'est pas tout à fait ce que vous cherchiez, mais il a l'avantage de pouvoir fournir des implémentations par défaut si l'utilisation obscure que vous avez en tête l'exige. Je pensais aussi qu'il y aurait un problème de dissimulation de noms dans l'alternative si vous dériviez de «test», mais à la réflexion il n'y aurait pas de problème. –

+0

Lol. Agréable! Totalement oublié de superposer le pré-processeur sur le dessus.Merci de me le rappeler! :) – Carl

Questions connexes