开发者

How do I use a class as a value to be used on set::find()? - C++

So I'm working on a project and I have to use the set library on class objects. Those object开发者_StackOverflows have many attributes, ID being one of them.

What I wanted to do was search for an object inside a "set" by its ID. The problem is set only has find and I don't know how to search for an ID this way since I'd have to use find(class object) and not find(int). I tried messing with class operators to read it as an object but couldn't find a way.

Also, I thought about algorithm::find_if, but that would just check every element from beggining to end instead of using the set "tree" search functions, right?

Thanks in advance.


You'll have to use the second template argument to specify a comparison functor. See the ltstr example on this page


From your description, you might want to consider using a std::map or std::unordered_map, with your "ID" as the key and your class object as the value.


If your class is already compatable with a set then you have defined the operator< or have provided a specific comparitor for comparing elements using a strict weak ordering.

struct X
{
    X(int pid): id(pid) {} 
    int id;
    bool operator<(X const& rhs) { return this->id < rhs.id;}
};

std::set<X>  data;
std::set<X>::const_iterator find = data.find(X(12));
if (find != data.end())
{
       // You found the item
}

This has the drawbacks in that you need to define X in a way that you can easily create temporary objects with a specific ID and the operator< (or the comparitor) is just a strict weak ordering of the ID.

An alternative is to use std::find_if() with a custom comparitor:

struct TestXID
{
    TestXID(int testId): tid(testId) {}
    bool operator()(X const& item) const {return tid == item.id;}
    int  tid;
};

std::set<X>::const_iterator find = std::find(data.begin(),data.end(),TestXID(5));
if (find != data.end())
{
       // You found the item
}


You need to create a constructor for your class that takes int as its only argument. Doing so allows implicit conversion from int to your class, making it possible to call std::set::find(int), as requested.

For example:

#include <iostream>
#include <set>

class Foo {
  public:
    /* Normal constructor */
    Foo(const char * s, int i) : str(s),id(i) {}
    /* Special constructor for implicit conversion */
    Foo(int i) : str(0),id(i) {}
    /* Make Foo usable with std::set */
    bool operator<(const Foo& f) const { return f.id<id; }
    /* Make Foo printable */
    friend std::ostream& operator<<(std::ostream& o, const Foo& f);
  private:
    const char * str;
    int id;
};
std::ostream& operator<<(std::ostream& o, const Foo& f) { 
  return o << "(" << f.str << " " << f.id << ")";
}

typedef std::set<Foo> FooSet;
int main(void) {
  FooSet s;
  s.insert(Foo("test",1));
  s.insert(Foo("asdf",7));
  s.insert(Foo("spam",3));
  for (int i=0; i<10; ++i) {
    /* Note that searching is done via FooSet::find(int id) */
    FooSet::const_iterator f = s.find(i);

    std::cout << "Searching for id " << i << ": ";
    if (f==s.end())
      std::cout << "absent";
    else
      std::cout << "present " << *f;
    std::cout << std::endl;
  }
  return 0;
}

This yields:

Searching for id 0: absent
Searching for id 1: present (test 1)
Searching for id 2: absent
Searching for id 3: present (spam 3)
Searching for id 4: absent
Searching for id 5: absent
Searching for id 6: absent
Searching for id 7: present (asdf 7)
Searching for id 8: absent
Searching for id 9: absent
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜