Syntax for finding structs in multisets - C++ - c++

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.

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 );

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
}

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
}

Related

How to define an common iterator to my class hirerachy

My team designed a library meant to store data from different "signals". A signal is a list of timestamped float values. We have three way to store a signal (depending of the way it was recorded from the hardware in the first place):
MarkerSignal: We store a sorted std::vector of std::pair of (boost::posix_time::ptime,float)
RawSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration) and finally a std::vector of float (each value's timestamp is start time + period * value's index in the vector)
NumericalSignal: We store a start time (boost::posix_time::ptime), a sampling period (boost::posix_time::time_duration), a scale (float), an offset (float) and finally a std::vector of short (timestamp is computed as for RawSignal and float value is short*scale+offset)
Those three signals have a common parent class (SignalBase) storing the signal's name, description, unit and stuff like that. We use the visitor pattern to let people nicely "cast" the SignalBase to a MarkerSignal/RawSignal/NumericalSignal and then access the data it contains.
In the end, what we need for each class is to iterate through all elements, one element being actually a pair of (boost::posix_time::ptime,float) (like MarkerSignal). And it's a pain having to create a visitor every time we want to do that.
Storing all signals as a std::vector<std::pair<boost::posix_time::ptime,float>> (or returning an object of this kind on demand) uses too much memory.
We thought the best was probably to define our own iterator object. The iterator would give access to the timestamp and value, like that:
SignalBase* signal = <any signal>;
for ( SignalBase::iterator iter = signal->begin();
iter != signal->end();
++iter )
{
boost::posix_time::ptime timestamp = iter.time();
float value = iter.value();
}
What's the best approach/strategy to create such an iterator class? (simple class with a size_t index attribute, or a MarkerSignal/RawSignal/NumericalSignal container's specific iterator as attribute, store a std::pair<boost::posix_time::ptime,float> and update it from a ++ operator...).
Also, I would much prefer if the solution rpoposed avoids using a virtual table (to have ++, time(), and value() be faster when iterating on huge signals).
To sum up I think the best you can achieve if you value for efficiency could be something like this:
template <typename SignalType, typename Functor = function<void(typename SignalType::value_type&&) > >
void iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
Then for call:
iterateThroughSignal<MarkerSignal>(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
I'm not sure if you are using C++11 so the lambda can be replace by function pointer, rvalue reference using lvalue reference and the std::function with a function signature...
Edit:
To make it compile when the type of the foo signature won't match the SignalType::value_type there will be a need of playing a little bit with sfinae:
template <typename SignalType>
class IterateHelper {
template <typename Functor>
static typename enable_if<first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
SignalType *specificSignal = dynamic_cast<SignalType *>(signal);
if (!specificSignal)
return;
for (typename SignalType::iterator it = specificSignal->begin();
it != specificSignal->end();
it++) {
foo(*it); // retrieving value from iterator...
}
}
template <typename Functor>
static typename enable_if<!first_param_is<Functor, typename SignalType::value_type>::value >::type iterateThroughSignal(SignalBase *signal, Functor foo) {
}
};
I leave the implementation of first_param_is helper struct to you... Call would change to:
IteratorHelper<MarkerSignal>::iterateThroughSignal(signal, [](MarkerSignal::value_type&& msv){
/*doing something with value...*/
});
As I wanted something easy to use for people using my library (be able to esily do a for loop) I finally implemented my own iterator like that:
Added two virtual functions in SignalBase (found no alternative to that, runtime will use the virtual table):
virtual size_t floatDataCount() const = 0;
virtual bool loadFloatInfoAt( size_t pos, SignalFloatIter::ValueInfo& info ) const = 0;
Added functions in SignalBase to get begin/end iterators:
inline BDL::SignalFloatIter beginFloatIter() const { return BDL::SignalFloatIter::beginIter( *this ); }
inline BDL::SignalFloatIter endFloatIter() const { return BDL::SignalFloatIter::endIter( *this ); }
Declared iterator class like that:
class SignalFloatIter
{
public:
SignalFloatIter( const SignalBase* signal = NULL, size_t pos = 0 );
SignalFloatIter( const SignalFloatIter& iter );
static SignalFloatIter beginIter( const SignalBase& signal );
static SignalFloatIter endIter( const SignalBase& signal );
SignalFloatIter& operator=( const SignalFloatIter& iter );
bool operator==( const SignalFloatIter& iter ) const;
bool operator!=( const SignalFloatIter& iter ) const;
/** Pre-increment operator */
SignalFloatIter& operator++();
/** Post-increment operator */
SignalFloatIter operator++(int unused);
inline const BDL::time& when() const { assert( m_valid ); return m_info.first.first; }
inline const BDL::duration& duration() const { assert( m_valid ); return m_info.first.second; }
inline const float& value() const { assert( m_valid ); return m_info.second; }
inline size_t index() const { assert( m_valid ); return m_pos; }
inline BDL::MarkerKey markerKey() const { assert( m_valid ); return std::make_pair( when(), duration() ); }
inline bool valid() const { return m_valid; }
typedef std::pair<BDL::time,BDL::duration> TimeInfo;
typedef std::pair<TimeInfo,float> ValueInfo;
private:
const SignalBase* m_signal;
size_t m_pos;
bool m_valid;
ValueInfo m_info;
void loadCurInfo();
};
Implemented:
SignalFloatIter::SignalFloatIter( const SignalBase* signal, size_t pos ) :
m_signal( signal ),
m_pos( pos )
{
loadCurInfo();
}
SignalFloatIter::SignalFloatIter( const SignalFloatIter& iter )
{
operator=( iter );
}
SignalFloatIter SignalFloatIter::beginIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, 0 );
}
SignalFloatIter SignalFloatIter::endIter( const SignalBase& signal )
{
return SignalFloatIter( &signal, signal.floatDataCount() );
}
SignalFloatIter& SignalFloatIter::operator=( const SignalFloatIter& iter )
{
if ( this != &iter )
{
m_signal = iter.m_signal;
m_pos = iter.m_pos;
m_info = iter.m_info;
m_valid = iter.m_valid;
}
return *this;
}
bool SignalFloatIter::operator==( const SignalFloatIter& iter ) const
{
if ( m_signal == iter.m_signal )
{
if ( m_pos == iter.m_pos )
{
assert( m_valid == iter.m_valid );
if ( m_valid )
assert( m_info == iter.m_info );
return true;
}
else
{
return false;
}
}
else
{
assert( false );
return false;
}
}
bool SignalFloatIter::operator!=( const SignalFloatIter& iter ) const
{
return !( *this == iter );
}
SignalFloatIter& SignalFloatIter::operator++()
{
++m_pos;
loadCurInfo();
return *this;
}
SignalFloatIter SignalFloatIter::operator++( int unused )
{
SignalFloatIter old = *this;
assert( unused == 0 ); // see http://en.cppreference.com/w/cpp/language/operator_incdec
++m_pos;
loadCurInfo();
return old;
}
void SignalFloatIter::loadCurInfo()
{
if ( m_signal )
{
m_valid = m_signal->loadFloatInfoAt( m_pos, m_info );
}
else
{
assert( false );
m_valid = false;
}
}
It's pretty straightforward and easy to use for any signal:
std::cout << "Signal timestamped data are: ";
for ( BDL::SignalFloatIter iter = signal.beginFloatIter();
iter != signal.endFloatIter();
++iter )
{
std::cout << iter.when() << " : " << iter.value() << std::endl;
}

Use std::find on vector<class> to find matching class attribute [duplicate]

Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.

How to find an instance of a class with specific member values in a std::vector [duplicate]

Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.

Sorting a list of structs

Hi I have a C++ code where there is a struct and list of structs. In my struct, the first element is a string. In list of struct, how do I sort with the first element of the structure so that after sorting all the elements in the list will be arranged alphabetically? please find piece of sample code below. thanks in advance.
struct samplestruct
{
string Name;
int Number
};
samplestruct obj_samplestruct;
vector<samplestruct> List;
obj_samplestruct.Name = "Tom";
obj_samplestruct.Number = 1;
list.push_back(obj_samplestruct);
obj_samplestruct.Name = "Jerry";
obj_samplestruct.Number = 2;
list.push_back(obj_samplestruct);
obj_samplestruct.Name = "Tom";
obj_samplestruct.Number = 3;
list.push_back(obj_samplestruct);
Now in the above code how do I sort as per Name in structure so that in list the members should be arranged alphabatically..
The sort function requires something that can be called with two arguments and returns a bool, this could be a lambda function:
sort( list.begin( ), list.end( ),
[]( const samplestruct& a, const samplestruct&b ){
return a.Name < b.Name;
} );
By default it looks for an operator<, so this would work as well:
bool operator<( const samplestruct& a, const samplestruct&b ){
return a.Name < b.Name;
}
sort( list.begin( ), list.end( ) );
The following code should solve your problem:
struct samplestruct_lessThan
{
bool operator()(samplestruct const & a, samplestruct const & b) const
{
return a.Name < b.Name;
}
};
std::sort(object.begin(), object.end(), samplestruct_lessThan());
Others,
struct samplestruct{
string Name;
int Number;
bool operator<( const samplestruct& a) const {
//just + 'const': maybe patch for the bug of GCC(clang-802.0.42)
return Name < a.Name;
}
};
sort( );

Vectors, structs and std::find

Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.