Home » C++ programming language: The automatically generated equality operator

C++ programming language: The automatically generated equality operator

by admin
C++ programming language: The automatically generated equality operator

C++ programming language: The automatically generated equality operator

Most C++ developers will be familiar with the fact that the three-way comparison operator can be defined or requested by the compiler using =default. What is probably less known is that the equality operator can also be defined or requested in C++20?

Advertisement

Before I discuss the automatically generated equality operator, I would like to brush up on the key facts about the three-way comparison operator.

Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also enjoys speaking frequently at specialist conferences. On his blog Modern C++ he deals intensively with his passion C++.

The three-way comparison operator can be defined or requested from the compiler with =default. In both cases you get all six comparison operators: ==, !=, and >=.

// threeWayComparison.cpp

#include
#include

struct MyInt {
int value;
explicit MyInt(int val): value{val} { }
auto operator(const MyInt& rhs) const { // (1)
return value rhs.value;
}
};

struct MyDouble {
double value;
explicit constexpr MyDouble(double val): value{val} { }
auto operator(const MyDouble&) const = default; // (2)
};

template
constexpr bool isLessThan(const T& lhs, const T& rhs) {
return lhs The user-defined (1) and compiler-generated (2) three-way comparison operators work as expected.

However, there are a few notable differences between the two three-way comparison operators. The compiler-inferred return type for MyInt (1) supports strict ordering, but the compiler-inferred return type for MyDouble (2) only supports partial ordering. Floating point numbers can only support partial ordering because values ​​like NaN (Not a Number) cannot be ordered. For example, NaN == NaN evaluates to false.

See also  Linux Kernel at risk: New vulnerability! Vulnerability allows Denial of Service

The three-way comparison operator produced by the compiler, which is implicitly constexpr and noexcept, requires the header . He also carries out a lexicographical comparison. In this context, lexicographic comparison means that all base classes are compared from left to right and all non-static members are compared in the order in which they are declared.

Let’s say I add a std::unordered_set to the two classes MyInt and MyDouble.

struct MyInt {
int value;
std::unordered_set mySet;
explicit MyInt(int val): value{val}, mySet{val} { }
bool operator(const MyInt& rhs) const {
if (auto first = value rhs.value; first != 0) return first;
else return mySet rhs.mySet;
}
};

struct MyDouble {
double value;
std::unordered_set mySet;
explicit MyDouble(double val): value{val}, mySet{val} { }
bool operator(const MyDouble&) const = default;
};

Requesting or defining three-way comparison fails because std::unordered_set does not support ordering. std::unordered_set only supports equality comparisons, and this also applies to MyInt and MyDouble.

If the equality operator is defined or requested by the compiler with =default, you automatically get the equality and inequality operators: ==, and !=.

// equalityOperator.cpp

#include
#include
#include

struct MyInt {
int value;
std::unordered_set mySet;
explicit MyInt(int val): value{val}, mySet{val} { }
bool operator==(const MyInt& rhs) const {
return std::tie(value, mySet) == std::tie(rhs.value, rhs.mySet);
}
};

struct MyDouble {
double value;
std::unordered_set mySet;
explicit MyDouble(double val): value{val}, mySet{val} { }
bool operator==(const MyDouble&) const = default;
};

template
constexpr bool areEqual ( const T & lhs , const T & rhs ) { return lhs == rhs ; } template
constexpr bool areNotEqual(const T& lhs, const T& rhs) {

return lhs != rhs;
}

int main() {

std::cout Now I can compare MyInt and MyDouble for equality and inequality.

I used a trick in the equalityOperator.cpp program – who recognizes it?

In the example below, I implemented MyInt’s equality operator by concatenating the equality operators of value and mySet.

See also  Microsoft towards EU investigation into Teams. And slow down the acquisition of Activision

struct MyInt {
int value;
std::unordered_set mySet;
explicit MyInt(int val): value{val}, mySet{val} { }
bool operator==(const MyInt& rhs) const {
if (auto first = value == rhs.value; first != 0) return first;
else return mySet == rhs.mySet;
}
};

This is quite error-prone and looks ugly if you have a class with multiple members.

In contrast, I used std::tie to implement the equality operator in the equalityOperator.cpp program.

struct MyInt {
int value;
std::unordered_set mySet;
explicit MyInt(int val): value{val}, mySet{val} { }
bool operator==(const MyInt& rhs) const {
return std::tie(value, mySet) == std::tie(rhs.value, rhs.mySet);
}
};

std::tie creates a tuple of lvalue references to its arguments. Finally, the generated tuples are compared lexicographically.

In my next article I will continue my journey through C++20 and write about std::span. std::span represents an object that refers to a contiguous sequence of objects. (map)

To home page

You may also like

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More

Privacy & Cookies Policy