2015-08-17 3 views
1

Tenir compte de ce code:VARIADIC Héritage

#include <iostream> 

class Religion { 
    public: 
     virtual void pray() = 0; 
}; 

// Example: Denomination<N0,N1,N2,N3> is derived from Denomination<N0,N1,N2> is derived 
// from Denomination<N0,N1> is derived from Denomination<N0> is derived from Religion. 
template <int...> class Denomination : public Religion { 
    virtual void pray() {std::cout << "Prays like a ... ?\n";} 
}; 

template <> class Denomination<2> : public Religion { 
    virtual void pray() override {std::cout << "Prays like a Muslim.\n";} 
}; 

template <> class Denomination<2,0> : public Denomination<2> { 
    virtual void pray() override {std::cout << "Prays like a Sunni Muslim.\n";} 
}; 

template <> class Denomination<2,0,1> : public Denomination<2,5> { 
    virtual void pray() override {std::cout << "Prays like a Hanafi Sunni Muslim.\n";} 
}; 

template <int...> struct D {}; 

class Person { 
    Religion* religion; 
public: 
    template <int... Is> 
    Person (const D<Is...>&) : religion(new Denomination<Is...>) {} 
     // How to get the Flyweight Pattern here? 
    void pray() {religion->pray();} 
}; 

int main() { 
    Person* person1 = new Person(D<2,0,1>{}); // "Prays like a Hanafi Sunni Muslim." 
    Person* person2 = new Person(D<2,0>{}); // "Prays like a Sunni Muslim." 
    Person* person3 = new Person(D<2>{}); // "Prays like a Muslim." 
    person1->pray(); 
    person2->pray(); 
    person3->pray(); 

    Person* person4 = new Person(D<2,5,6,2,1,3>{}); 
    person4->pray(); // Should be "Prays like a Hanafi Sunni Muslim." 
} 

Je veux changer le constructeur Person à

Person (const D<Is...>&) : religion(findDenomination<Is...>()) {} 

qui recherchera une "table" de Religion* statique s. Après tout, 2 personnes appartenant à la même dénomination devraient partager la même valeur Religion*. Donc, c'est le modèle de conception mouche que j'essaie de mettre en œuvre ici. Le problème est que nous ne savons pas longtemps le pack Is... est (le nombre de sous-sous -...- dénominations n'est pas fixé n'importe où), donc un simple tableau multidimensionnel ne fonctionnera pas je ne pense pas. Donc, ce que je fais, c'est placer des vecteurs const statiques de Religion* dans les classes appropriées et le pack Is... sera utilisé pour trouver le vecteur final à rechercher.

Mise à jour: Toutes les meilleures façons de le faire? La solution que j'ai trouvée jusqu'ici a un inconvénient majeur si vous voyez ci-dessous.

+2

L'orthographe de 'pray()' comme 'proie()' m'a fait sourire. Ou voulez-vous vraiment dire qu'ils se nourrissent les uns les autres? :-) – dave

Répondre

0

Ok, j'ai mis au point une solution presque complète. Person* person4 = new Person(D<2,0,1,2,1,3>{}); ne fonctionne plus cependant. Cette personne est supposée être une sous-sous-catégorie d'un musulman sunnite hanafi, qui est censé par défaut prier comme un musulman sunnite hanafi en raison de l'absence (intentionnelle) de surcharge pour Denomination<2,0,1,2,1,3>. J'ai encore besoin d'aide pour compiler person4 pour compiler cependant

#include <iostream> 
#include <vector> 
#include <type_traits> 

class Religion { 
    public: 
     virtual void pray() = 0; 
}; 

template <int...> class Denomination : public Religion { 
    virtual void pray() {std::cout << "Prays like a ... ?\n";} 
}; 

template <> class Denomination<0> : public Religion { 
    virtual void pray() override {std::cout << "Prays like a Christian.\n";} 
}; 

template <> class Denomination<0,0> : public Denomination<0> { 
    virtual void pray() override {std::cout << "Prays like a Catholic.\n";} 
}; 

template <> class Denomination<0,1> : public Denomination<0> { 
    virtual void pray() override {std::cout << "Prays like a Protestant.\n";} 
}; 

template <> class Denomination<2> : public Religion { 
    virtual void pray() override {std::cout << "Prays like a Muslim.\n";} 
}; 

template <> class Denomination<2,0> : public Denomination<2> { 
    virtual void pray() override {std::cout << "Prays like a Sunni Muslim.\n";} 
}; 

template <> class Denomination<2,0,1> : public Denomination<2,5> { 
    virtual void pray() override {std::cout << "Prays like a Hanafi Sunni Muslim.\n";} 
}; 

template <int...> struct ReligionDatabase; 

template <> struct ReligionDatabase<> { 
    static const std::vector<Religion*> denominations; 
}; 
const std::vector<Religion*> ReligionDatabase<>::denominations = {new Denomination<0>, new Denomination<1>, new Denomination<2>}; 

template <> struct ReligionDatabase<0> { 
    static const std::vector<Religion*> denominations; 
}; 
const std::vector<Religion*> ReligionDatabase<0>::denominations = {new Denomination<0,0>, new Denomination<0,1>}; 

template <> struct ReligionDatabase<2> { 
    static const std::vector<Religion*> denominations; 
}; 
const std::vector<Religion*> ReligionDatabase<2>::denominations = {new Denomination<2,0>, new Denomination<2,1>, new Denomination<2,2>}; 

template <> struct ReligionDatabase<2,0> { 
    static const std::vector<Religion*> denominations; 
}; 
const std::vector<Religion*> ReligionDatabase<2,0>::denominations = {new Denomination<2,0,0>, new Denomination<2,0,1>, new Denomination<2,0,2>}; 

template <int...> struct D {}; 
template <typename Output, int... Input> struct RemoveLastHelper; 

template <int... Accumulated, int First, int... Rest> 
struct RemoveLastHelper<D<Accumulated...>, First, Rest...> : RemoveLastHelper<D<Accumulated..., First>, Rest...> {}; 

template <int... Accumulated, int Last> 
struct RemoveLastHelper<D<Accumulated...>, Last> : std::integral_constant<int, Last> { 
    using type = D<Accumulated...>; 
}; 

template <int... Is> 
using RemoveLast = RemoveLastHelper<D<>, Is...>; 

class Person { 
    template <typename> struct GetReligion; 
    Religion* religion; 
public: 
    template <int... Is> Person (const D<Is...>&) : Person(RemoveLast<Is...>{}) {} 
    template <typename T> Person (const T&) : religion(GetReligion<typename T::type>::get(T::value)) {} 
    void pray() {religion->pray();} 
}; 

template <int... Is> 
struct Person::GetReligion<D<Is...>> { 
    static Religion* get(int n) {return ReligionDatabase<Is...>::denominations[n];} 
}; 

int main() { 
    Person* person1 = new Person(D<2,0,1>{}); // "Prays like a Hanafi Sunni Muslim." 
    Person* person2 = new Person(D<2,0>{}); // "Prays like a Sunni Muslim." 
    Person* person3 = new Person(D<2>{}); // "Prays like a Muslim." 
    person1->pray(); 
    person2->pray(); 
    person3->pray(); 

// Person* person4 = new Person(D<2,0,1,2,1,3>{}); // This doesn't compile. 
// person4->pray(); // Should be "Prays like a Hanafi Sunni Muslim." 

    Person* person5 = new Person(D<0>{}); 
    Person* person6 = new Person(D<0,1>{}); 
    person5->pray(); // "Prays like a Christian." 
    person6->pray(); // "Prays like a Protestant." 
} 
J'ai besoin du compilateur pour réduire en quelque sorte le Denomination<2,0,1,2,1,3> à Denomination<2,0,1>. Comment faire cela?