在C++中,当键是带字符串的结构时,如何在带函子的映射上使用find_if

In C++, how to use find_if on a map with a functor when keys are struct with strings?

本文关键字:映射 if find C++ 结构 字符串      更新时间:2023-10-16

我有一个stl::map,它的键类型是自定义结构。我想知道这个映射是否已经有一个以特定字符串作为组件的键(下面记为"id"(,不管它的其他组件的值是多少。受这个答案和这个答案的启发,我尝试将stl::find_if与自定义functor:一起使用

map<myStruct, vector<size_t> > myMap;
struct myStruct
{
  string a, b, c, id;
};
struct checkId : unary_function<pair<myStruct, vector<size_t> >, bool>
{
private:
  string _exp;
public:
  checkId (myStruct x) : _exp(x.id) {}
  bool operator() (const pair<myStruct, vector<size_t> > & p) const
  {
    return p.first.id.compare(_exp) == 0;
  }
};
map<myStruct, vector<size_t> >::iterator it;
myStruct newS;  // to be initialized, but not shown here
it_mP2P = find_if(myMap.begin(), myMap.end(), checkId(newS));

当我编译这个时,gcc会返回我:

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = myStruct]’:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_map.h:347:    instantiated from ‘_Tp& std::map<_Key,_Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = myStruct, _Tp = std::vector<long unsigned int, std::allocator<long unsigned int> >, _Compare = std::less<myStruct>, _Alloc = std::allocator<std::pair<const myStruct, std::vector<long unsigned int, std::allocator<long unsigned int> > > >]’
myprogram.cpp:386:    instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_function.h:227:  error: no match for ‘operator<’ in ‘__x < __y’

这是否意味着,如果我想使用我的函子"checkId",我必须重载运算符"<"才能使用我的自定义结构?我该怎么做?我不是C++专家,所以提前感谢您提供的任何代码。

http://codepad.org/VYNqdZeF

struct myStruct
{
  std::string a, b, c, id;
  bool operator<(const myStruct& rhs) const //HERES THE MAGIC
  {return id < rhs.id;}                     //WHEEEEEEEEEEEE!
};

这是使std::map<myStruct, stuff>在不传递自定义比较函子的情况下工作所必需的。

它与checkId无关。下面展示了相同的问题:

map<myStruct, vector<size_t> > myMap;
struct myStruct
{
  string a, b, c, id;
};

std::map是一个排序的映射(它通常被实现为二进制搜索树(。。。密钥类型(在这种情况下为myStruct(必须具有简单地实现的CCD_ 7来构造映射。

如果您不需要快速查找,您可以使用vector< pair< myStruct, vector<size_t> > >;如果需要快速查找,则必须向myStruct添加某种类型的结构。对于std::map,这必须是一个比较运算符;或者,您可以使用std::unordered_map(在C++11中;这通常是作为哈希表实现的(——在这种情况下,您需要实现一个哈希函数。

有关更多详细信息,请参阅std::mapstd::unordered_map的文档。

这与find_if的使用无关。

对于要成为映射的键的类型,它需要是可比较的,或者通过实现运算符<或者通过提供比较器作为映射的模板参数。

Mooing Duck的答案是最简单的,但不是最灵活的

如果你去写

struct myStruct
{
  std::string a, b, c, id;
  bool operator<(const myStruct& rhs) const
  {return id < rhs.id;}                    
};

那么所有以myStruct为关键字的地图都必须进行排序通过CCD_ 16。

假设您有一个映射需要a进行比较,另一个映射则需要b进行比较。如果您将operator<()放入myStruct中,那么您将结构与其用户紧密耦合,这不是一种好的编程实践。

相反,您可以为每个地图设置一个比较函数:

struct myStruct
{
  std::string a, b, c, id;   // keep your struct unchanged, and independent of clients
};
bool Compare_by_a(const myStruct &s1, const myStruct& s2)  {
  return s1.a < s2.a;
}                    
bool Compare_by_b(const myStruct &s1, const myStruct& s2)  {
  return s1.b < s2.b;
}                    
bool Compare_by_id(const myStruct &s1, const myStruct& s2)  {
  return s1.id < s2.id;
}                    
map<myStruct, vector<size_t>, Compare_by_a > map1;
map<myStruct, vector<size_t>, Compare_by_b > map2;
map<myStruct, vector<size_t>, Compare_by_id > map3;