Variadic Inheritance

Рассмотрим этот код:

#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*s. В конце концов, 2 человека, принадлежащие к одной и той же конфессии, должны иметь одинаковые Religion* значение. Так что я пытаюсь реализовать этот шаблон проектирования в навесном весе. Проблема в том, что мы не знаем долго Is... pack — это (число под-sub -…- деноминаций нигде не зафиксировано), так что простой многомерный массив не будет работать, я не думаю. Поэтому вместо этого я размещаю статические константные векторы Religion*S в соответствующих классах и Is... Пакет будет использоваться, чтобы найти последний вектор для поиска.

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

1

Решение

Хорошо, я разработал почти полное решение. 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>, Как это сделать?

0

Другие решения


По вопросам рекламы [email protected]