Reputation: 1644
I can't seem to figure out the syntax for finding structs in containers.
I have a multiset of Event
structs. I'm trying to find one of these structs by searching on its key. I get the compiler error commented below.
struct Event {
public:
bool operator < ( const Event & rhs ) const {
return ( time < rhs.time );
}
bool operator > ( const Event & rhs ) const {
return ( time > rhs.time );
}
bool operator == ( const Event & rhs ) const {
return ( time == rhs.time );
}
double time;
int eventID;
int hostID;
int s;
};
typedef std::multiset< Event, std::less< Event > > EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
EventPQ::iterator ceItr = currentEvents.find( EventPQ::key_type( oldRecTime ) ); // no matching function call
I've tried a few permutations to no avail. I thought defining the conditional equality operator was going to be enough.
Solution
After correcting my typo (sorry), I now have a solution closest to AraK's, augmented by Soapbox's suggested use of explicit
:
struct Event {
explicit Event(double t) : time(t), eventID(), hostID(), s() {}
Event(double t, int eid, int hid, int stype) : time(t), eventID( eid ), hostID( hid ), s(stype) {}
...
};
EventPQ::iterator ceItr = currentEvents.find( EventPQ::key_type( Event(oldRecTime) ) );
I recently discovered that another option would have been to use find_if
, discussed here.
Thanks for the help.
Upvotes: 2
Views: 1513
Reputation: 96889
You don't have a suitable constructor that accepts double
. Just add the following constructor:
Event(double t) : time(t), eventID(/**/), hostIDeventID(/**/), s(/**/)
{ }
Here is how Event would look like:
struct Event {
public:
// Initialize other variables as needed
Event(double t) : time(t), eventID(/**/), hostIDeventID(/**/), s(/**/)
{ }
bool operator < ( const Event & rhs ) const {
return ( time < rhs.time );
}
bool operator > ( const Event & rhs ) const {
return ( time > rhs.time );
}
bool operator == ( const Event & rhs ) const {
return ( time == rhs.time );
}
double time;
int eventID;
int hostID;
int s;
};
// No need for std::less because it is used by default,
// when you define 'operator <' in your class
typedef std::multiset< Event > EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
// You can just pass the double, a temporary object will be created
// for you.
EventPQ::iterator ceItr = currentEvents.find( oldRecTime );
Upvotes: 3
Reputation: 20609
You seem to have multiset and multimap confused. Multiset is for when the key and the value are one-and-the-same. Multimap is for when a key and a value are associated, but not the same object.
In this case, Event isn't actually the key. The "time" double appears to be the key. Since the key and the value are not exactly the same, you should use a multimap. Using event as both the key and value doesn't make sense here.
You don't want to construct an event with extra fields you don't need just to search for a given value. Instead, multimap lets you search using the double, which is what you really want. This also eliminates the need for less than operators in the Event class.
Your code would then look something like this:
struct Event {
double time;
int eventID;
int hostID;
int s;
};
typedef std::multimap<double, Event> EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
std::pair<EventPQ::iterator, EventPQ::iterator> results = currentEvents.equal_range(oldRecTime);
for(EventPQ::iterator cur = results.first; cur != results.second; ++cur) {
// do something to *cur
}
Upvotes: 0
Reputation: 99044
Besides the missing constructor, you don't want to call find()
on the iterator ceItr
but on currentEvents
:
EventPQ::iterator ceItr = currentEvents.find(EventPQ::key_type(oldRecTime));
Note that find()
only gives you an iterator to the first match, use equal_range()
to get a range of all matches:
std::pair<EventPQ::iterator, EventPQ::iterator> result;
result = currentEvents.find(EventPQ::key_type(oldRecTime));
for(EventPQ::iterator it = result.first; it != result.second; ++it) {
// do stuff
}
Upvotes: 2