C++ overloading operator< error - c++

Why am I receiving an error when I do not put const in the function bool operator<(const Node& otherNode) //const?
stl_algo.h:91: error: passing 'const Node' as 'this' argument of 'bool Node::operator<(const Node&)' discards qualifiers
Should all the overloaded operators be constant?
class Node {
public:
double coordinate;
bool operator==(const Node& other) const{
return coordinate == other.coordinate;
}
bool operator<(const Node& other) const{
return coordinate < other.coordinate;
}
};

Not all operators, but == and < should definitely be made const, yes. They logically don't modify either of the objects being compared.
The error likely comes from calling a non-const method from a const one, e.g.:
bool isSmaller(const Node& other) const
{
return *this < other;
}
In this case, since the method isSmaller is const, this is implicitly a const object, therefore operator < also has to be const in order for the call within that context to be valid.
From the error message, it appears that Node::operator < is being called on a const object, from a function in stl_algo.h - sorting/ordering functions, hashing functions, etc.

Comparison operators, such as <, >, <=, >=, ==, != should operate on const objects in general, because it makes no sense if any objects being compared can be changed by the comparison. But you could declare the comparisons as non-member functions in order to ensure symmetry between both operands.
class Node {
public:
double coordinate;
};
inline operator<(const Node& lhs, const Node& rhs)
{
return lhs.coordinate < rhs.coordinate;
}

Have you try to delete the const modifier of the method? Also, as #LuchianGrigore sugest, you can use the this keyword:
bool operator< (const Node& other) {
return this.coordinate < other.coordinate;
}

Related

Overloading less than operator in c++ for use in std::sort

I have a struct defined like this:
struct IFSFunc {
int a;
bool operator<(const IFSFunc& other) {
return a < other.a;
}
};
Since IFSfunc is a struct, access modifier for the operator< should be public.
I also have this code:
#include <algorithm>
std::vector<std::pair<double, IFSFunc>> ifsFuncs;
// fill the vector with various data
std::sort(ifsFuncs.begin(), ifsFuncs.end());
I need to sort ifsFuncs based on the first double in the pair. I don't care about IFSFunc structure, if the double is the same.
However, for std::sort to work, which is defined like this:
template <class _Ty1, class _Ty2>
_NODISCARD constexpr bool operator<(const pair<_Ty1, _Ty2>& _Left, const pair<_Ty1, _Ty2>& _Right) {
return _Left.first < _Right.first || (!(_Right.first < _Left.first) && _Left.second < _Right.second);
}
I have to override the less than operator for the second in this case IFSfunc, which I did. However, trying to compile this code gives me the following error:
Error C2678 binary '<': no operator found which takes a left-hand operand of type 'const _Ty2' (or there is no acceptable conversion)
Why?
You need to define that operator as a const member function.
Also, don't just return true for a comparison. That can result in infinite looping.
I just figure it out. The overloaded function signature was wrong, this is what I need:
struct IFSFunc {
int a;
bool operator<(const IFSFunc& other) const {
return a < other.a;
}
};
Notice that the operator< is now a const function.

Can I compare 2 structures in C++?

I have simply declared a structure like this -
struct data{
int x,y;
};
Now I have declared 2 variables a & b of data type. I've assigned appropriate values to them. Now, I want to check if they are equal! I am trying to do like this -
data a,b;
a.x=12, a.y=24;
b.x=15, b.y=30;
if(a!=b)cout<<"a~b"<<endl;
But the compiler is giving me the following error on the 4th line ->
error: no match for 'operator!=' (operand types are 'data' and 'data')
Where is the problem actually? Isn't this compare supported in C++?? Or I'm making any mistakes??
What is the exact and easiest way to do this?? Do I need to compare each of the elements in the structure separately?? Or there's any other smarter way??
C++ gives you attribute-by-attribute assignment implicitly, but no comparison for equality or ordering. The reason is "just because", don't look too hard into philosophy.
You must to provide those operators, if needed, by implementing them yourself explicitly, for example:
bool operator<(const Data& other) const {
if (x < other.x) return true;
if (x > other.x) return false;
return y < other.y;
}
bool operator==(const Data& other) const {
return x == other.x && y == other.y;
}
and so on.
Note also that defining for example == doesn't give you != automatically and defining < doesn't provide >= implicitly.
UPDATE
C++20 introduces (will introduce) a new operator <=> (friendly name "spaceship operator") exactly to remove the verbosity of having to define all possible relational operators. In this case adding:
std::strong_ordering operator<=>(const Data& other) const {
if (auto cmp = x <=> other.x; cmp != 0) return cmp;
return y <=> other.y;
}
will allow compilation of all relational tests (<, <=, >, >=, ==, !=) between elements of the class based on checking x first and, if that check doesn't resolve, checking y instead.
You have to implement all operators explicitely that you intent to use. In your case, you will need to supply bool operator!=(const data&, const data&).
A nice way to implement it for PODs like this is to use std::tuple since it already implements ordering:
#include <tuple>
// ...
bool operator!=(const data& p_lhs, const data& p_rhs)
{
return std::tie(p_lhs.x, p_lhs.y) != std::tie(p_rhs.x, p_rhs.y);
}
std::tie (documentation) creates a temporary tuple of references. Those two tuples can then be compared, since std::tuple defines all comparison operators, as shown here.
I chose to implement operator!= as a free function. You can, of course, choose to implement it as member of your class:
struct data
{
bool operator!=(const data& p_rhs) const
{
return std::tie(x, y) != std::tie(p_rhs.x, p_rhs.y);
}
int x, y;
};
Of course you should define all other operators, too. Remember that you can implement most operators by delegating to others.
Automatic C++ comparisons are coming in C++20, so you can just add a special operator to indicate that you need default comparisons when new standard is out.
class Point {
int x;
int y;
public:
auto operator<=>(const Point&) const = default;
// ... non-comparison functions ...
};
https://en.cppreference.com/w/cpp/language/default_comparisons
You have to implement bool operator != (const data&, const data&);.
Possible implementation (in c++11):
#include <tuple>
//...
bool operator == (const data& lhs, const data& rhs) {
return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y);
}
bool operator != (const data& lhs, const data& rhs) {
return !(lhs == rhs);
}

How to create custom class used with std set copy assignment?

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.

C++ doesnt overload operator

For some reason, the custom compare seems to be skipped. Never is the debug string printed and the sorting is off.
Can anyone spot what is wrong here?
bool Communication::operator<(const Communication& second) const
{
qDebug() << "Actually sorting";
return (getName().compare(second.getName()) < 0);
}
class Communication
{
public:
bool operator<(const Communication& second) const;
QString getName() const;
void setName(QString nm);
QString commName;
}
void Communication::addComm(vector<Communication*>c)
{
// This is called for sure
lg=c;
std::sort ( lg.begin(), lg.end());
}
Edit:
Below my new approach.
bool Communication::cmp(const Communication* lhs, const Communication* rhs) const
{
return (lhs->getName().compare(rhs->getName()) < 0);
}
...error: no matching function for call to 'sort(std::vector<Communication*>::iterator, std::vector<Communication*>::iterator, <unresolved overloaded function type>)'
Your vector contains pointers:
vector<Communication*> c
but your comparison is for values. You need to implement a comparison for pointers, but this cannot be operator< because you cannot overload that operator for pointers. It should be a function or functor.
bool cmp(const Communication* lhs, const Communication* rhs)
{
return (lhs->getName().compare(rhs->getName()) < 0);
}
std::sort ( lg.begin(), lg.end(), cmp);
Operators won't be overloaded for operators. If you want to sort a sequence of pointers based on a predicate on the pointees you'll need to use a suitable predicate function, e.g.:
std::sort(lg.begin(), lg.end(),
[](Communication const* c0, Communication const* c1){
return *c0 < *c1;
});
You are sorting a vector of Communication*, but your operator< compares const Communication&.

Error using std::find with operator==

I am getting an error using std::find on the following structure ...
struct ComplianceOrderRecord {
explicit ComplianceOrderRecord(IOrder& order);
bool operator ==(const ComplianceOrderRecord& other) const;
double price;
};
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}
I use it as follows...
inline void Compliance::RemoveComplianceOrderRecord(const ComplianceOrderRecord& order) {
auto it = std::find(m_compliantOrderList.begin(),
m_compliantOrderList.end(), order);
if(it == m_compliantOrderList.end()) {
return;
}
m_compliantOrderList.erase(it);
}
The error is...
error C2679: binary '==' : no operator found which takes a right-hand operand of type 'const ComplianceOrderRecord' (or there is no acceptable conversion)
Any help in understanding this error would be very appreciated.
Your operator== should be a const member, or even better, a freestanding function.
This error can be reproduced if m_compliantOrderList is not a container<ComplianceOrderRecord >. (Perhaps it is a container of pointers, or some other completely unrelated class.
Edit:
Your equality operator can compare two instances of ComplianceOrderRecord, but find needs to compare a pointer against an object. Overloading an operator to perform this kind of comparison would be bizarre, so you could use find_if with a custom predicate, such as:
struct RecordIsEqualTo
{
const ComplianceOrderRecord* record;
RecordIsEqualTo(const ComplianceOrderRecord& r): record(&r) {}
bool operator() (const ComplianceOrderRecord* r) const { return *record == *r; }
};
std::find_if(m_compliantOrderList.begin(), m_compliantOrderList.end(),
RecordIsEqualTo(order) );
or a lambda version thereof.
Your operator== function should be const. As it is, you can't call it on a const object (or a reference to const.
Try a const method:
inline bool ComplianceOrderRecord::operator ==(const ComplianceOrderRecord& other) const {
return price == other.price;
}