Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Policy-based template design: How to access certain policies of the class?

I have a class that uses several policies that are templated. It is called Dish in the following example. I store many of these Dishes in a vector (using a pointer to simple base class), but then I'd like to extract and use them. But I don't know their exact types.

Here is the code; it's a bit long, but really simple:

#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;
}

The tricky part is here, in the main() function:

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

How can I access the dessert? I don't even know the Dessert type (it is templated), let alone the complete type of the object that I'm getting from the storage.

This is just a toy example, but I think my code reduces to this. I'd just like to pass those Dish classes around, and different parts of the code will access different parts of it (in the example: its appetizer, main dish, or dessert).

like image 417
Frank Avatar asked Mar 06 '10 23:03

Frank


1 Answers

What you have is not exactly policy-based design IMO... if it were, your class should've actually implemented (i.e. extended) the policies.

Now, back to your question/example. In your container, you store a "DishBase*". Right? From that point on, you loose any compile-time information wrt the actual type of the objects in the collection. So, I'm afraid what you try to do is provably impossible.

What you could do, is use an actual policy-based design, eg.

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

Then, you could simply use dynamic_cast to check at runtime that you can convert your object to any concrete Appetizer/Dessert/Main.

But from your description, I get the impression that you actually need abstract base classes (i.e. abstract base classes may be the design that makes sense for you, and not policies).

like image 61
Virgil Avatar answered Sep 27 '22 16:09

Virgil