使用带boost::shared_ptr的基类在映射中查找
Find in a map using the base class with a boost::shared_ptr
我正在寻找一种方法来找到一个元素内部使用基类的映射(下面的代码只是一个基本的例子):
#include <map>
#include <boost/shared_ptr.hpp>
class Base {
public:
Base(int v) : id(v) {};
int id;
};
class Derived : public Base {
public:
Derived(int v) : Base(v) {};
};
int main()
{
std::map<boost::shared_ptr<Derived>, double> m;
m.insert(std::make_pair(boost::shared_ptr<Derived>(new Derived(1)), 10));
m.insert(std::make_pair(boost::shared_ptr<Derived>(new Derived(2)), 20));
auto b1 = boost::shared_ptr<Base>(new Base(1));
m.find(b1);
return 0;
}
基本上,我想比较id
属性。编译器返回的错误如下:
main.cpp: In function 'int main()':
main.cpp:35:14: error: no matching function for call to 'std::map<boost::shared_ptr<Derived>, double>::find(boost::shared_ptr<Base>&)'
m.find(b1);
^
main.cpp:35:14: note: candidates are:
In file included from /usr/include/c++/4.8/map:61:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/stl_map.h:820:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&) [with _Key = boost::shared_ptr<Derived> _Tp = double; _Compare = std::less<boost::shared_ptr<Derived> > _Alloc = std::allocator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::key_type = boost::shared_ptr<Derived>]
find(const key_type& __x)
^
/usr/include/c++/4.8/bits/stl_map.h:820:7: note: no known conversion for argument 1 from 'boost::shared_ptr<Base>' to 'const key_type& {aka const boost::shared_ptr<Derived>&}'
/usr/include/c++/4.8/bits/stl_map.h:835:7: note: std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&) const [with _Key = boost::shared_ptr<Derived> _Tp = double; _Compare = std::less<boost::shared_ptr<Derived> > _Alloc = std::allocator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const boost::shared_ptr<Derived>, double> > std::map<_Key, _Tp, _Compare, _Alloc>::key_type = boost::shared_ptr<Derived>]
find(const key_type& __x) const
^
/usr/include/c++/4.8/bits/stl_map.h:835:7: note: no known conversion for argument 1 from 'boost::shared_ptr<Base>' to 'const key_type& {aka const boost::shared_ptr<Derived>&}'
如果您想使用您的映射查找id
,您需要传递一个适当的比较函数,以便映射按id
排序其键而不是默认的operator <
(我认为,将所有权块地址与boost::shared_ptr
参数进行比较)。
所以像这样改变地图:
struct Less_id
{
bool operator() (const boost::shared_ptr<Derived> &lhs, const boost::shared_ptr<Derived> &rhs) const
{
return lhs->id < rhs->id;
}
};
typedef std::map<boost::shared_ptr<Derived>, double, Less_id> Map;
Map m;
这将相应地排序映射,但仍然不允许通过Base
指针查找。为此,您可以在std::lower_bound
:
Map::const_iterator find_base(const Map &map, const boost::shared_ptr<Base> &base)
{
auto it = std::lower_bound(
map.begin(), map.end(), base,
[](const Map::value_type &lhs, const boost::shared_ptr<Base> &rhs)
{ return lhs.first->id < rhs->id; }
);
if (it != map.end() && it->first->id == base->id)
return it;
else
return map.end();
}
std::lower_bound()
用于保持std::map::find()
提供的对数复杂度。
生活例子/strong>
使用
std::map<boost::shared_ptr<Derived>, double, std::less<boost::shared_ptr<Base>>>
编辑:我领先于时代-这只适用于c++ 14
需要克服两个问题。第一种情况是,您希望在Derived
集合中搜索Base
。第二个是您希望按值而不是按地址进行比较。其他答案都忽略了第二个点。试试std::find_if
:
auto b1 = boost::shared_ptr<Base>(new Base(1));
auto itFound = std::find_if(m.begin(), m.end()
[=](const std::pair<boost::shared_ptr<Derived>, double>& pair)
{
// omitting null checks for this example
return pair.first->id == b1->id;
});
如果要求只是查找具有给定id的键,则可以简化为:
int queryKey = 1;
auto itFound = std::find_if(m.begin(), m.end()
[=](const std::pair<boost::shared_ptr<Derived>, double>& pair)
{
return pair.first->id == queryKey;
});
现在,正如在评论中所指出的,这将为您提供线性而不是map
通常的对数查找时间。如果地图很小,这没关系,但如果这是一个问题,你可以使用std::lower_bound
而不是find_if
。注意,这还需要添加自定义比较器,以便确保映射的排序顺序是基于id的。例如:
struct Compare
{
bool operator()(const boost::shared_ptr<Derived>& l,
const boost::shared_ptr<Derived>& r) const
{
// omitting null checks for this example
return l->id < r->id;
}
};
std::map<boost::shared_ptr<Derived>, double, Compare> m;
这是因为boost::shared_ptr的操作符<不是您想要的,您需要委托给派生类的操作符<
use std::map<_Key, _Tp, _Compare>
例如:
std::map<boost::shared_ptr<Derived>, double, compare_func()> m;
当你正在寻找一个对象Base
,它只能在地图中,如果它是Derived
类型,你可以简单地这样做:
boost::shared_ptr<Derived> d1 = boost::dynamic_pointer_cast<Derived>(b1);
if(d1) {
m.find(d1);
} else {
// not in the map
}
当您使用
std::shared_ptr<Derived>
作为键时,另一种可能性是实际使用指向基类的指针:
使用
std::map<boost::shared_ptr<Base>, double> m;
不是
std::map<boost::shared_ptr<Derived>, double> m;
一切正常
顺便说一句,你在Base
中缺少一个virtual
析构函数!
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 如何使用基类指针引用派生类成员
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- C++通过映射并使用中的方法从基类实现派生类
- 使用具有抽象基类指针的映射并调用派生类函数
- C++-智能指针的矢量映射-所有这些都继承自同一基类
- C++11:使用中央命令映射器调用虚拟基类方法
- 包含抽象基类ptr_map的映射对象
- std::基类指针映射
- 将Qt基类信号映射到派生类中的槽
- 使用带boost::shared_ptr的基类在映射中查找