2015-08-17 7 views
1

Рассмотрим этот код:VARIADIC Наследование

#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." 
} 

Так что я хочу, чтобы изменить Person конструктор

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

, который будет выглядеть вверх "стол" статических Religion* с. В конце концов, 2 человека, принадлежащие к одному и тому же наименованию, должны иметь одинаковое значение Religion*. Так что это шаблон дизайна мухи, который я пытаюсь реализовать здесь. Проблема в том, что мы не знаем давно, что пакет Is... (количество суб-суб-деноминаций нигде не фиксировано), поэтому простой многомерный массив не будет работать, я не думаю. Поэтому вместо того, что я делаю, помещают некоторые статические константные векторы Religion* s в соответствующие классы, а пакет Is... будет использоваться для поиска конечного вектора для поиска.

Обновление: Есть ли лучшие способы сделать это? Решение, которое я нашел до сих пор, имеет большой недостаток, если вы видите ниже.

+2

Написание 'pray()' as 'prey()' заставило меня улыбнуться. Или вы действительно имели в виду, что они охотятся друг на друга? :-) – dave

ответ

0

Хорошо, я разработал почти полное решение. Person* person4 = new Person(D<2,0,1,2,1,3>{}); больше не работает. Предполагается, что этот человек является под-подкатегорией мусульманина-суннита Ханафи, который, как предполагается, молится, как мусульманин-суннит Ханафи, из-за (намеренного) отсутствия переоценки для Denomination<2,0,1,2,1,3>.

#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." 
} 

Я все еще нужна помощь, чтобы получить person4 компилировать, хотя. Мне нужен компилятор, чтобы как-то уменьшить Denomination<2,0,1,2,1,3> до Denomination<2,0,1>. Как это сделать?

 Смежные вопросы

  • Нет связанных вопросов^_^