unordered_map和虚拟模板

时间:2011-06-07 10:21:26

标签: c++ stl

问题是:我想使用unordered_map来存储键和值,其中键可以是A类或B类,具体取决于用户选项。 A类和B类都继承自同一个P类。

class A: public P {...}
class B: public P {...}

我想用抽象P类定义地图,然后根据运行时选项,为那里指定一个带有A或B作为关键字的地图:

unordered_map< P, CValue, P::hash, P::equal_to> * pmap = new unordered_map< A, CValue, A::hash, A::equal_to>;

但我会收到错误:

 cannot convert ... in initialization

如何宣布这样的“虚拟”地图?

2 个答案:

答案 0 :(得分:3)

以下是一个示例,说明如何使地图在P*上键入,但仍然在派生类中使用不同的实现:

struct P
{
  virtual size_t hash_self() const = 0;
  virtual bool equal(const P &) const = 0;
};

struct A : public P
{
  inline bool operator==(const A & other) const { return false; /*Implement!*/}
  size_t hash_self() const { return 1; /*Implement!*/ }
  bool equal(const P & p) const { return *this == dynamic_cast<const A &>(p); }
};

struct PHash
{
  size_t operator()(const P * const p) const { return p->hash_self(); }
};

struct PEqual
{
  bool operator()(const P * const p, const P * const q) const { return p->equal(*q); }
};


#include <unordered_map>

std::unordered_map<P *, double, PHash, PEqual> pmap{{ new A, .5 }};

动态强制转换是有效的,因为您只承诺比较相同派生类型的指针。

如果你想变得更干净,你可能会专攻std::hash<P*>std::equal_to<P*>

namespace std
{
  template<> struct hash<P*>
  { size_t operator()(P * const & p) const { return p->hash_self(); } };

  template<> struct equal_to<P*> : public binary_function<P*, P*, bool>
  { bool operator()(P * const & p, P * const & q) const { return p->equal(*q); } };
}

std::unordered_map<P *, int> qmap{{new A, -11}}; // just works!

答案 1 :(得分:2)

unsorted_map< P, CValue, P::hash, P::equal_to> * pmap = new unsorted_map< A, CValue, A::hash, A::equal_to>;

类型P与类型A不同。

所以X<P>X<A>的类型不同。这意味着,这段代码

X<P> *pX = new X<A>();
即使A来自P

也无法编译。 GCC会给出这个错误(ideone):

error: cannot convert ‘X<A>*’ to ‘X<P>*’ in initialization

如果您知道X<A>X<P>完全不同,则不言自明。

请注意,A来自P。但X<A>仍未来自X<P>。我认为你把后者与前者混为一谈。

所以我认为你需要的是:

unorder_map<P*, P::hash, P::equal_to>  objectMap;

您可以将A*类型的对象插入此地图:

objectMap.insert(new A());

您还可以插入B*类型的对象:

objectMap.insert(new B());

毕竟,您希望以多态方式处理地图中的所有对象。