简体   繁体   中英

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 objects 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

根据您的描述,您可能要考虑使用std :: map或std :: unordered_map,将“ ID”作为键,并将类对象作为值。

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM