C++ finding class in vector using std::find raises errors - c++

I'm trying to find a SnekNode object in an std::vector using
auto it = std::find(snek_node_container.begin(), snek_node_container.end(), snek_node);
but it raises a compiler error:
Error C2676 binary '==': 'SnekNode' does not define this operator or a
conversion to a type acceptable to the predefined operator
which points to the xutility file as source which is not very helpful. When I try to define a == function in the class such as:
SnekNode operator== (const SnekNode& rhs) {
return (*this == rhs);
}
I get another compilation error:
C2451 conditional expression of type "SnekNode" is illegal
which also points to the xutility file which again, sadly doesn't help me. What am I doing wrong here? Thanks in advance!

operator== should return bool.
Also, you need to compare the members individually. In your code you just call operator== again, causing infinite recursion.
What you can do is use the operator== in operator!= to save typing, e.g.:
struct SnekNode
{
bool operator== (const SnekNode& rhs) const {
return a == rhs.a &&
b == rhs.b &&
c == rhs.c;
}
bool operator!= (const SnekNode& rhs) const {
return !(*this == rhs);
}
// auto operator<=>(const SnekNode&) const = default; // C++20
int a{0};
int b{1};
int c{2};
};
With C++20 you can use default comparisons (spaceship operator).
Live demo

Related

generate == operator that uses non-defaulted <=>

In a slight variation of this question. I would like to define a custom type with a custom <=> operator and use that custom <=> operator to generate a ==. Trying the following
#include <compare>
#include <iostream>
#include <cassert>
struct widget {
int member;
int non_comparison_data;
friend std::strong_ordering operator<=>(const widget& lhs,
const widget& rhs) {
std::cout << "doing a three way comparison" << std::endl;
return lhs.member <=> rhs.member;
}
// friend bool operator==(const widget& lhs, const widget& rhs) {
// return 0 == (lhs <=> rhs);
// }
friend bool operator==(const widget& lhs, const widget& rhs) = default;
};
int main() {
widget a{.member = 1, .non_comparison_data = 23};
widget b{.member = 1, .non_comparison_data = 42};
assert(a==b);
return 0;
}
I observe that a default == operator does not use the custom <=> operator, but instead does what would be done in absence of any custom comparison and compares all data members. I can define an operator == on my own that uses <=> like follows, but I'm wondering if there's a better way to get == out of <=>.
friend bool operator==(const widget& lhs, const widget& rhs) {{
return 0 == (lhs <=> rhs);
}
PS: compiler-explorer link
PS: I'm aware a custom <=> doesn't generate a default == because == is likely implementable in a more optimal way than using <=> and one does not want an inefficient default to be generated.
I'm wondering if there's a better way to get == out of <=>.
Nope, there's not. What you did (return 0 == (lhs<=>rhs);) is the optimal way. What more were you looking for?
The only way to define == in terms of <=> is to do it manually. Which is what you're already doing.
You can do a little bit better by writing member functions (the only benefit of non-member friends would be if you wanted to take by value. But if you're not doing that, member functions are easier - simply less code to write). And then implement == forwards instead of backwards... no Yoda conditionals please.
struct widget {
int member;
int non_comparison_data;
std::strong_ordering operator<=>(const widget& rhs) const {
return member <=> rhs.member;
}
bool operator==(const widget& rhs) const {
return (*this <=> rhs) == 0;
}
};

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

Practical reason for defining operator!=

The following code will fail to compile under GCC because it does define operator== but does not define operator!=.
struct A {
unsigned int m_i;
bool operator == (const A& rhs) const { return m_i == rhs.m_i; }
};
bool f(const A& lhs, const A& rhs) { return lhs != rhs; }
Obviously it wants either
bool operator != (const A& rhs) const { return !(operator==(rhs)); }
or
bool operator != (const A& rhs) const { return m_i != rhs.m_i; }
Common wisdom seems to be that this is because !operator== adds an instruction and so is less efficient. This leads some programmers to dutifully write out their complex != expression in full, and over the years I've fixed a number of bugs resulting from mismatched operators.
Is this coercion to write both operators a case of premature/legacy optimization, or is there a good, solid, practical reason to do this code-doubling that I'm just somehow missing ?
I would say absent some overwhelming evidence to the contrary, it's purely premature optimization (not even legacy--I doubt there was ever a good reason for it, at least in anything approaching a C++ time-frame).
For what it's worth, ยง20.2.1 of the C++ standard defines a number of overloads in <utility> that will give you a != based on operator== and a >, >=, <= all based on operator<.
Why not use this:
bool f(const A& lhs, const A& rhs) { return !(lhs == rhs); }

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