I am creating a min heap from stl priority queue. Here is my class which I am using.
class Plane
{
private :
int id ;
int fuel ;
public:
Plane():id(0), fuel(0){}
Plane(const int _id, const int _fuel):id(_id), fuel(_fuel) {}
bool operator > (const Plane &obj)
{
return ( this->fuel > obj.fuel ? true : false ) ;
}
} ;
In main I instantiate an object thus.
priority_queue<Plane*, vector<Plane*>, Plane> pq1 ;
pq1.push(new Plane(0, 0)) ;
I am getting an error from xutility which I am unable to understand.
d:\microsoft visual studio 10.0\vc\include\xutility(674): error C2064: term does not evaluate to a function taking 2 arguments
Any help to its solution would be appreciated.
If you drop the use of pointers (which are overkill for your simple structures), then you can use std::greater from the header functional:
std::priority_queue<Plane, std::vector<Plane>, std::greater<Plane> > pq1;
pq1.push(Plane(0, 0));
Currently, you are feeding Plane as the comparison type. That won't work since the comparison type must be a type of function object, i.e. it must have an operator() that does the comparison. Plane doesn't have such a member (and adding it just for this purpose would be a bad idea).
std::greater has the appropriate method, implemented in terms of your operator>. However, it doesn't work with pointers, because then it uses a pointer comparison (based on memory addresses).
Btw., note that your comparison function can be expressed more succinctly as
bool operator>(const Plane &other)
{
return fuel > other.fuel;
}
The third template parameter must be a binary functor taking teo Plane*. Your Plane class does not provide that.
You need something of the form
struct CompPlanePtrs
{
bool operator()(const Plane* lhs, const Plane* rhs) const {
return lhs->fuel > rhs->fuel ;
}
};
Related
I am having trouble sorting a list of custom class pointers. The class I need to sort are events. These get assigned a random time and I need to do them in the right order.
#include <list>
Class Event{
public:
float time; // the value which I need to sort them by
int type; // to indicate which event i'm dealing with
Event(float tempTime, int tempType)
{
time = tempTime;
type = tempType;
}
int main(){
std::list<Event*> EventList;
list<Event*>::iterator it;
.........
If you could help me sort this out it would be much appreciated! I've been stuck on this for hours now.
Thanks!
Since the list contains pointers, rather than objects, you'll have to provide a custom comparator to compare the objects they point to. And since you're using a list, you have to use its own sort method: the generic std::sort algorithm only works on random-access sequences.
EventList.sort([](Event * lhs, Event * rhs) {return lhs->time < rhs->time;});
or, if you're stuck in the past and can't use lambdas:
struct CompareEventTime {
bool operator()(Event * lhs, Event * rhs) {return lhs->time < rhs->time;}
};
EventList.sort(CompareEventTime());
If the list contained objects (as it probably should), then it might make sense to provide a comparison operator instead:
bool operator<(Event const & lhs, Event const & rhs) {return lhs.time < rhs.time;}
std::list<Event> EventList;
//...
EventList.sort();
You should to that with std::sort. You can either make a custom comparator function that you pass as third argument to the std::sort function, or you can make a < operator overload for your class and std::sort will work naturally.
I have following situation:
#include <list>
struct Example
{
double p1;
double p2;
};
void f()
{
std::list<Example> list1;
std::list<Example> list2;
list1.merge(list2);
}
During build I get errors:
C2672 'operator __surrogate_func': no matching overloaded function found
C2893 Failed to specialize function template 'unknown-type std::less<void>::operator() (_Ty1 &&,_Ty2&&) const'
If I comment the last line of code, the build is successful. I find it hard to believe that lists that contain objects cannot be merged, so: what am I missing?
PS. I use Visual Studio Community 2015
As stated in documentation std::list::merge:
Merges two sorted lists into one.
And further:
The first version uses operator< to compare the elements
So you either need to provide operator< for your structure or use overloaded version with custom comparator. For example standalone function could be:
bool operator<( const Example &e1, const Example &e2 ) {
return std::tie( e1.p1, e1.p2 ) < std::tie( e2.p1, e2.p2 );
}
A possible way out of the problem is to define a meaningful relational operator< that defines order of your class Example objects. This could be done by:
An overloaded operator< withing the class, which will be implicitly used.
Lambda expression directly inserted as a second parameter in the merge() function.
Separate comparison class, whose object instantiation could be used as second parameter in merge()
For example, you could do something like:
bool operator< (const Example& lhs, const Example& rhs) const
{
return lhs.p1 < rhs.p1; // if p1 is used as a criterion
}
give std::list::merge a way to compare
class Examples{...};
for example, you can do this by passing in a lambda
void f()
{
std::list<Example> list1;
std::list<Example> list2;
list1.merge(list2,[](Example e1,Example e2)
{
return (e1.p1==e2.p1)? (e1.p2 < e2.p2) : (e1.p1 < e2.p1);
});
}
or you can just do
using Example = std::pair<double,double>;
and then std::list::merge will already know how to compare these (assuming you want the default comparison rules for std::pair)
I have a simple class that I am storing in a vector as pointers. I want to use a find on the vector but it is failing to find my object. Upon debugging it doesn't seem to call the == operator I've provided. I can 'see' the object in the debugger so I know its there. The code below even uses a copy of the first item in the list, but still fails. The only way I can make it pass is to use MergeLine* mlt = LineList.begin(), which shows me that it is comparing the objects and not using my equality operator at all.
class MergeLine {
public:
std::string linename;
int StartIndex;
double StartValue;
double FidStart;
int Length;
bool operator < (const MergeLine &ml) const {return FidStart < ml.FidStart;}
bool operator == (const MergeLine &ml) const {
return linename.compare( ml.linename) == 0;}
};
Class OtherClass{
public:
std::vector<MergeLine*>LineList;
std::vector<MergeLine*>::iterator LL_iter;
void DoSomething( std::string linename){
// this is the original version that returned LineList.end()
// MergeLine * mlt
// mlt->linename = linename;
// this version doesn't work either (I thought it would for sure!)
MergeLine *mlt =new MergeLine(*LineList.front());
LL_iter = std::find(LineList.begin(), LineList.end(), mlt);
if (LL_iter == LineList.end()) {
throw(Exception("line not found in LineList : " + mlt->linename));
}
MergeLine * ml = *LL_iter;
}
};
cheers,
Marc
Since your container contains pointers and not objects, the comparison will be between the pointers. The only way the pointers will be equal is when they point to the exact same object. As you've noticed the comparison operator for the objects themselves will never be called.
You can use std::find_if and pass it a comparison object to use.
class MergeLineCompare
{
MergeLine * m_p;
public:
MergeLineCompare(MergeLine * p) : m_p(p)
{
}
bool operator()(MergeLine * p)
{
return *p == *m_p;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineCompare(mlt));
I think what you really want is to use std::find_if like this:
struct MergeLineNameCompare
{
std::string seachname;
MergeLineNameComp(const std::string &name) : seachname(name)
{
}
bool operator()(const MergeLine * line)
{
return seachname.compare( line->linename ) == 0;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineNameCompare(linename) );
The operator == (no matter wich form) is better saved for real comparison of equality.
Operator overloading can't work with pointers as it is ambiguous.
Bjarne Stroustrup :-
References were introduced primarily to support operator overloading.
C passes every function argument by value, and where passing an object
by value would be inefficient or inappropriate the user can pass a
pointer. This strategy doesn’t work where operator overloading is
used. In that case, notational convenience is essential so that a user
cannot be expected to insert address− of operators if the objects are
large.
So, may be not best but still :-
std::vector<MergeLine>LineList;
std::vector<MergeLine>::iterator LL_iter;
I am having trouble sorting a list of custom class pointers. The class I need to sort are events. These get assigned a random time and I need to do them in the right order.
#include <list>
Class Event{
public:
float time; // the value which I need to sort them by
int type; // to indicate which event i'm dealing with
Event(float tempTime, int tempType)
{
time = tempTime;
type = tempType;
}
int main(){
std::list<Event*> EventList;
list<Event*>::iterator it;
.........
If you could help me sort this out it would be much appreciated! I've been stuck on this for hours now.
Thanks!
Since the list contains pointers, rather than objects, you'll have to provide a custom comparator to compare the objects they point to. And since you're using a list, you have to use its own sort method: the generic std::sort algorithm only works on random-access sequences.
EventList.sort([](Event * lhs, Event * rhs) {return lhs->time < rhs->time;});
or, if you're stuck in the past and can't use lambdas:
struct CompareEventTime {
bool operator()(Event * lhs, Event * rhs) {return lhs->time < rhs->time;}
};
EventList.sort(CompareEventTime());
If the list contained objects (as it probably should), then it might make sense to provide a comparison operator instead:
bool operator<(Event const & lhs, Event const & rhs) {return lhs.time < rhs.time;}
std::list<Event> EventList;
//...
EventList.sort();
You should to that with std::sort. You can either make a custom comparator function that you pass as third argument to the std::sort function, or you can make a < operator overload for your class and std::sort will work naturally.
I'm making a program that generates a maze and then uses bredth first search to find a way in the maze. My function that checks if an element is present in a container-class now uses the vector like this (where coordinatePath is a typedef for vector) :
bool Labyrinth::inVisited(const Coordinate &c, const coordinatePath &visited ) const
{
for each (Coordinate coord in visited)
{
if(coord == c)
return true;
}
return false;
}
Since this method has to traverse the full container if an element is not present it's very ineffective for large searches. I tried to implement the same function that uses a set instead of a vector and wrote it like this:
bool Labyrinth::inVisited(const Coordinate &c, const set<Coordinate> &visited ) const
{
return (visited.find(c) != visited.end());
}
when i try to recomplie i get a lot of errors where the topmost is
Error 22 error C2676: binary '<' : 'const Coordinate' does not define this operator or a conversion to a type acceptable to the predefined operator c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstddef 193
I don't really understand these particular debug-messages and wonder if there is a way to implement this faster search!
In order to create a std::set of objects, those objects have to define operator <.
So you need to add the following operator:
inline bool operator < (const Coordinate& first, const Coordinate& other);
To use elements in a set the value_type has to define operator< or you need to provide a comparison functor to the container. Apparently, your Coordinate type doesn't do that or the operator< you provide takes incompatible arguments. It should look roughly like this:
struct Coordinate {
bool operator<(const Coordinate& other) const { return false; }
};
// or by providing a functor
struct CmpCoord {
bool operator()(const Coordinate& x, const Coordinate& y);
};
typedef std::set<Coordinate, CmpCoord> coord_set;