问题是:我想使用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
如何宣布这样的“虚拟”地图?
答案 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());
毕竟,您希望以多态方式处理地图中的所有对象。