Основанный на политике шаблонный дизайн: Как получить доступ к определенным политикам класса?

У меня есть класс, который использует несколько политик, которые являются шаблонными. Это называют Dish в следующем примере. Я храню многие из них Dishes в a vector (использование указателя на простой базовый класс), но затем я хотел бы извлечь и использовать их. Но я не знаю их точные типы.

Вот код; это немного длинно, но действительно просто:

#include <iostream>
#include <vector>

struct DishBase {
  int id;
  DishBase(int i) : id(i) {}
};

std::ostream& operator<<(std::ostream& out, const DishBase& d) {
  out << d.id;
  return out;
}

// Policy-based class:
template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase {
  Appetizer appetizer_;
  Main main_;
  Dessert dessert_;
public:
  Dish(int id) : DishBase(id) {}
  const Appetizer& get_appetizer() { return appetizer_; }
  const Main& get_main() { return main_; }
  const Dessert& get_dessert() { return dessert_; }
};

struct Storage {
  typedef DishBase* value_type;
  typedef std::vector<value_type> Container;
  typedef Container::const_iterator const_iterator;
  Container container;
  Storage() {
    container.push_back(new Dish<int,double,float>(0));
    container.push_back(new Dish<double,int,double>(1));
    container.push_back(new Dish<int,int,int>(2));
  }
  ~Storage() {
    // delete objects
  }
  const_iterator begin() { return container.begin(); }
  const_iterator end() { return container.end(); }  
};

int main() {
  Storage s;
  for(Storage::const_iterator it = s.begin(); it != s.end(); ++it){
    std::cout << **it << std::endl;
    std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??
  }
  return 0;
}

Хитрая часть здесь, в main() функция:

    std::cout << "Dessert: " << *it->get_dessert() << std::endl; // ??

Как я могу получить доступ к десерту? Я даже не знаю Десертный тип (он является шаблонным), уже не говоря о полном типе объекта, который я получаю от устройства хранения данных.

Это - просто игрушечный пример, но я думаю, что мой код уменьшает до этого. Я был бы точно так же, как для передачи их Dish классы вокруг, и различные части кода получат доступ к различным частям его (в примере: его закуска, основное блюдо или десерт).

7
задан Яois 1 July 2014 в 11:36
поделиться

3 ответа

Вам потребуются соответствующие функции-члены для запросов (в данном случае перегрузка для конкретного типа Dessert). Политики должны раскрывать способ обнаружения. Вот краткий пример:

#include <iostream>
using namespace std;

struct TA { virtual string foo() { return "TA::foo\n"; } };
struct DTA  : TA { virtual string foo() { return "DTA::foo\n"; } };

template <class T>
struct C {
    T t;
};

template <class T>
ostream& operator <<(ostream& o, C<T> c) {
    o << c.t.foo();
    return o;
}

int main(int argc, char* argv[]) 
{
    C<DTA> c;
    cout << c;
}
0
ответ дан 7 December 2019 в 16:41
поделиться

Насколько я понимаю, классы шаблонов на основе политик не очень дружелюбны к контейнерам. Я просто выбираю простой старый полиморфизм для такого рода вещей. Хотя я был бы заинтересован в решении.

РЕДАКТИРОВАТЬ: Возможно, не случайно я не могу найти какое-либо использование контейнеров stl в книге Александреску «Современный дизайн C ++».

РЕДАКТИРОВАТЬ2: Более подробную информацию о трении между полиморфизмом и универсальностью можно найти здесь http://www.artima.com/cppsource/type_erasure.html . Возможно, ваш контейнер может состоять из boost :: any объектов?

0
ответ дан 7 December 2019 в 16:41
поделиться

То, что у вас есть, не совсем основано на политиках дизайн IMO ... если бы это было так, ваш класс должен был бы фактически реализовать (т.е. расширить) политики.

Теперь вернемся к вашему вопросу / примеру. В вашем контейнере вы храните "DishBase *". Верно? С этого момента вы теряете любую информацию времени компиляции относительно фактического типа объектов в коллекции. Так что я боюсь, что то, что вы пытаетесь сделать, невозможно доказать.

Что вы могли бы сделать, так это использовать реальный дизайн на основе политик, например.

template<class Appetizer, class Main, class Dessert>
class Dish : public DishBase, Appetizer, Main, Dessert {
}

Затем вы можете просто использовать dynamic_cast для проверки во время выполнения, что вы можете преобразовать свой объект в любую конкретную закуску / десерт / основное блюдо.

Но из вашего описания у меня сложилось впечатление, что вам действительно нужны абстрактные базовые классы (т.е. абстрактные базовые классы могут иметь смысл для вас, а не политики).

3
ответ дан 7 December 2019 в 16:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: