I try to create a custom class used with std::set. I know I need to provide a custom comparator for it so I overloaded the operator<. But when I try to copy the set with the code set<Edge> a; set<Edge> b = a;,
I get the following error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__functional_base:63:21: Invalid operands to binary expression ('const Edge' and 'const Edge')
class Edge {
public:
Edge(int V, int W, double Weight):v(V),w(W),weight(Weight){}
int other(int vertex){ return v ? w : vertex == w;}
int v,w;
double weight;
friend std::ostream& operator<<(std::ostream& out, const Edge& e)
{
out<<e.v<<' '<<e.w<<' '<<"weight:"<<e.weight<<'\n';
return out;
}
bool operator<(const Edge& other)
{
return weight < other.weight;
}
};
Make
bool operator<(const Edge& other) const
as the comparison operator must be marked const. The keys in a std::set are const, so the operator< is invoked on a const instance, hence must be marked const.
Related
I have this struct
struct C {
int ID;
int age;
C(int ID, int age) : ID{ID}, age{age} {}
};
I use a comparator function for a multiset
bool fncomp (const C& lhs, const C& rhs) {
return lhs.age < rhs.age;
}
multiset<C, decltype(fncomp)*> ms{fncomp};
ms.emplace(1, 15);
...
// this works fine
ms.count(C(1, 15));
However if I use a class comparator, this is no longer working.
struct classcomp {
bool operator() (const C& lhs, const C& rhs) {
return lhs.age < rhs.age;
}
};
multiset<C, classcomp> ms;
ms.emplace(1, 15);
...
// error
// ms.count(C(1, 15));
Anything makes the two different?
Elaborating on my comment above:
multiset::count is a const member function, which means that it operates on a const multiset. This includes the member variables of the multiset. The comparator is a member variable of the multiset.
Since your classcomp::operator() is not marked const, it can't be called on a const object, and so it fails to compile.
This works for the function pointer example, because it's the pointer that is const in that case.
bool operator() (const C& lhs, const C& rhs) const {
return lhs.age < rhs.age;
}
This would fix things to compile in this link you provided, courtesy of #Marshall -> https://stackoverflow.com/a/71384594/10630957
I've created a Point class and overload his operator==, and a PointSet class that has an array of pointers to Point objects.
Now, when i want to compare between two object I'm running in to unexplained compilation error when I'm tring to compare A==B but not when B==A.
i.e when im fliping the order of the object the function work as ecxpected.
I didnt find any logic between this two cases.
This is Point and PointSet classes (diffrenet header files)
class Point{
public:
Point(int x, int y);
~Point();
bool operator==(const Point& point);
private:
int _x, _y;
};
class PointSet
{
public :
PointSet(const size_t startLen);
~PointSet();
int contains(const Point *point) const
private:
Point **_pointArray;
size_t _size;
};
this is the implementation of the operator==
bool Point::operator ==(const Point& point){
return (this->_x == point.get_x() && this->_y == point.get_y());
}
And this is the function where the problem occur
int PointSet::contains(const Point *point) const{
for (int i=0; i<_size;i++){
if (*point == *_pointArray[i]){ <-----HERE
return i;
}
}
return -1;
}
this ISN'T an error if(*_pointArray[i] == *point)
the compilation error is "Can't compare structures"
Your operator== should be a const function
Try to implement
bool operator==(const Point& lhs, const PointSet& rhs){ /* do actual comparison */ }
as a friend member function. Also include:
bool operator==(const PointSet& lhs, const Point& rhs){ /* do actual comparison */ }.
This is the way you guarantee it will work.
More about this can be found here.
Suppose I have the following class:
class Point{
private:
int x,y;
public:
int get_x() const {return x;}
int get_y() const {return y;}
Point() :x(0),y(0){}
Point(int x,int y):x(x),y(y){}
Point(const Point& P){
x = P.get_x();
y = P.get_y();
}
Point& operator= (const Point& P) {
x = P.get_x();
y = P.get_y();
return *this;
}
friend ostream& operator<<(ostream& os,const Point& P) {
os<<"["<<P.get_x()<<", "<<P.get_y()<<"]";
return os;
}
Point operator - (const Point &P){
return Point(x-P.get_x(),y-P.get_y());
}
friend bool operator > (const Point &A, const Point &B) {
return A.get_y()>B.get_y();
}
};
Here I used friend function. I can also use function without friend:
class Point{
...
bool operator > (const Point &B) const {
return y>B.get_y();
}
...
};
What are the differences between them in actual implementations? Also in the second method, the code won't compile without 'cont', why is that? Even after I changed the getter function into non-const function, it still won't compile without the 'const'.
As you've already noticed, comparison operator overloads can either be implemented as a member function or as a non-member function.
As a rule of thumb you should implement them as a non-member non-friend function where possible, as this increases encapsulation, and it allows (non-explicit) conversion constructors to be used on either side of the operator.
Say for instance your Point class for whatever reason had an int conversion constructor:
Point(int x);
With a non-member comparison operator you can now do the following:
Point p;
p < 3; // this will work with both a member and non-member comparison
3 < p; // this will **only** work if the comparison is a non-member function
You also seem to be confused about when to use const, again as a rule of thumb for comparison operators you should always use const wherever possible, because comparisons logically do not involve any change to the object.
As Point is a very small class you could also take it by value instead, so in order of most to least preferable your options are:
// Non-member, non-friend
bool operator>(Point const& A, Point const& B);
bool operator>(Point A, Point B);
// Non-member, friend
friend bool operator>(Point const& A, Point const& B);
friend bool operator>(Point A, Point B);
// Member
bool Point::operator>(Point const& B) const;
bool Point::operator>(Point B) const;
I am trying to initialize a priority_queue , Here is the code
class stdnt{
public:
int indx;
int c;
int lvl;
bool operator<(const stdnt &x)
{
return this->c > x.c;
}
};
priority_queue<stdnt> pq;
But its giving me error that passing const & discards qualifiers. How else am I supposed to do this?
You need to make the operator const so that it can be called on const instances or via const references or pointers to const:
bool operator<(const stdnt &x) const
^^^^^
Alternatively, make it a non-member:
bool operator<(const stdnt &lhs, const stdnt& rhs)
{
return lhs.c > rhs.c;
}
I have a class:
class Monster : public Player
{
public:
// Copy constructor - used for populating monster list in Game class
Monster(int newType)
{
type = newType;
canmove = true;
notforward = false;
}
int type;
bool operator==(const Monster& m) const {return type == m.type;}
bool operator!=(const Monster& m) const {return type != m.type;}
bool operator< (const Monster& m) const {return type < m.type;}
bool operator<=(const Monster& m) const {return type <= m.type;}
bool operator> (const Monster& m) const {return type > m.type;}
bool operator>=(const Monster& m) const {return type >= m.type;}
};
Some variables (like canmove and notforward) are inherited. Next, in a different class, I create a map of monsters:
map<pair<int, int>, Monster> monsters; // Pair used for x and y coordinate
monsters.insert(make_pair(10, 10), Monster(10));
// Error - No instance of overloaded function
How can I get the Monster instances into the monsters map? I added all the operator overloads just so I could insert, but it doesn't work!
Simple way is
monsters[make_pair(10, 10)] = Monster(10);
another way is
monsters.insert(make_pair(make_pair(10, 10), Monster(10)));
yet another is
monsters.insert(map<pair<int, int>, Monster>::value_type(make_pair(10, 10), Monster(10)));
Operator overloads are unnecessary, you do need to overload operator< for the key of a map but not for the value. I think maybe you got confused because two calls to make_pair are necessary in the second case.