基于策略的模板设计:如何访问该类的某些策略?

时间:2010-03-06 23:42:04

标签: c++ oop templates template-meta-programming policy

我有一个类,它使用了几个模板化的策略。在以下示例中称为Dish。我将许多Dish es存储在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; // ??

我怎样才能获得甜点?我甚至不知道Dessert类型(它是模板化的),更不用说我从存储中获取的完整类型的对象了。

这只是一个玩具示例,但我认为我的代码减少了。我只想传递那些Dish类,代码的不同部分将访问它的不同部分(在示例中:它的开胃菜,主菜或甜点)。

3 个答案:

答案 0 :(得分:3)

你所拥有的并不完全是基于政策的设计IMO ......如果是,你的班级应该实际实施(即扩展)政策。

现在,回到你的问题/例子。在容器中,存储“DishBase *”。对?从那时起,您将丢失集合中实际对象类型的编译时信息。所以,我担心你试图做的事情显然是不可能的。

可以做的事情,是使用基于策略的实际设计,例如。

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

然后,您可以简单地使用dynamic_cast在运行时检查您可以将对象转换为任何具体的Appetizer / Dessert / Main。

但是从你的描述中,我得到的印象是你实际上需要抽象基类(即抽象基类可能是对你有意义的设计,而不是政策)。

答案 1 :(得分:0)

您需要具有适当的成员函数来进行查询(在这种情况下是具体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;
}

答案 2 :(得分:0)

我的理解是基于策略的模板类不是非常容器友好的。我只是为这种事情选择普通的旧多态。我会对解决方案感兴趣。

编辑:在Alexandrescu的“Modern C ++ Desing”一书中,我找不到任何stl容器的使用,这可能并非巧合。

EDIT2:有关多态性与通用性之间摩擦的更多细节可以在http://www.artima.com/cppsource/type_erasure.html找到。您的容器可能由boost::any个对象组成吗?