I came up with the idea to define a generic comparison operator which would work with any type, for the fun of it.
#include <cstring>
#include <iostream>
class A
{
public:
A(int id) : id(id) {}
private:
int id;
};
template <class T>
inline bool operator==(const T& a, const T& b)
{
return memcmp(&a, &b, sizeof(a)) == 0; // implementation is unimportant (can fail because of padding)
}
int main()
{
std::cout << (A(10) == A(10)) << std::endl; // 1
std::cout << (A(10) == A(15)) << std::endl; // 0
}
I think this could be useful to get around the lack of default comparison operator in c++.
Is this a terrible idea? I wonder if doing this could break anything in some circumstances?
Doing this is indeed a terrible idea.
If some type does not define an equality operator, it is most likely because you cannot reasonably compare two objects of that type for equality.
Even for the case where the missing equality operator was an oversight by the implementer, any "catch-all" implementation you would come up with is highly unlikely to do something sensible.†
So to conclude: Don't do this! Compile time errors are better than runtime errors; instead of prematurely adding a most certainly broken "solution" hiding the actual problem, add actual solutions as the compile time errors occur.
†For starters, the solution you came up with fails for types with padding, types with overloaded unary operator&
, and any type that has some pointer or reference like member; or even types with any member or base of any of the aforementioned categories. So for a ton of stuff.
Let's take a perfectly normal class, say String
. It's implemented as you'd think, with a char*
that points to a new[]
'ed buffer.
Now compare two of them. Obviously, String("abc")==String("abc")
. Yet your implementation fails this test, as the two pointers differ.
Equality is defined by the class semantics, not by the bits directly inside the object.
Yes, it is a terrible idea:
in case of uninitialized pointer:
Here is one failing sample (so this code has two different outputs):
#include <cstring>
#include <iostream>
class A {
public:
A(int id) : id(id) {}
private:
int id;
A* a;
};
template <class T> inline bool operator==(const T &a, const T &b) {
return memcmp(&a, &b, sizeof(a)) == 0;
}
int main() {
std::cout << (A(10) == A(10)) << std::endl; // 1
std::cout << (A(10) == A(15)) << std::endl; // 0
}
output:
0
0
and chances for two same values of RAM initial contents for two pointers is highly unlikely, then the other output is:
1
0
As a slight aside, the nicest way I know of writing equality operators for classes with lots of members uses this idea (this code requires C++ 14):
#include <tuple>
struct foo
{
int x = 1;
double y = 42.0;
char z = 'z';
auto
members() const
{
return std::tie(x, y, z);
}
};
inline bool
operator==(const foo& lhs, const foo& rhs)
{
return lhs.members() == rhs.members();
}
int
main()
{
foo f1;
foo f2;
return f1 == f2;
}
Code on Compiler Explorer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With