Reputation: 149
I'm writing a HeartbeatManager
for my application (in visual studio). The data of 1 heartbeat is stored in a Heart
object. The Heart
objects are stored in an std::set
. For this reason, I am implementing the operator=
, operator<
and operator>
overloads.
When defining these functions you can only use const
members. I tried to do this but still get an error saying I'm not:
passing const HeartbeatManager::Heart' as 'this' argument of 'bool HeartbeatManager::Heart::operator<(const HeartbeatManager::Heart&)'
discards qualifiers [-fpermissive]
Here is the code. I don't see where I'm using a non-constant:
class HeartbeatManager
{
public:
class Heart
{
public:
Heart(const IPAddress _ip, const uint16_t _port, int _lifetime = 5000)
: ip(_ip), port(_port), lifetime(_lifetime) {}
const IPAddress ip;
const uint16_t port;
int lifetime;
/**
* Ages the Heart, returns whether it survived (lifetime after aging > 0)
*/
bool age(int ms)
{
this->lifetime -= ms;
return 0 < this->lifetime;
}
// overloaded operators so heart struct can be sorted and used in map
bool operator=(const Heart& o) {
return ip == o.ip && port == o.port;
}
bool operator<(const Heart& o) {
return (uint32_t)ip < (uint32_t)o.ip || (ip == o.ip && port < o.port);
}
bool operator>(const Heart& o) {
return (uint32_t)ip > (uint32_t)o.ip || (ip == o.ip && port > o.port);
}
};
void heartbeat(IPAddress ip, uint16_t port, int sec = 5000);
};
I'm very new to C++. So if this is a bad practice for making an object fit the set requirements feel free to let me know.
Upvotes: 2
Views: 758
Reputation: 16873
The Heart objects are stored in an std::set. For this reason I am implementing the =, < and > operators.
It's fine to define as many operators as you like (more operators do give your class more flexibility). However, the use of std::set
justifies only operator<
; a default set does not make use of "greater than" or "equal to" (which presumably is what you thought a single equal sign would mean).
When defining these functions you can only use const members. I tried to do this but still get an error saying I'm not:
Take a moment to think about what you are doing. You want to be able to compare two objects using syntax like A < B
. As you stated, these should be considered constants by operator<
. Emphasis on "these". There are two objects. There should be two const
qualifications. Let's take a look at the operator declaration mentioned in the error message:
bool HeartbeatManager::Heart::operator<(const HeartbeatManager::Heart&)
How many times does "const
" appear in that declaration? Only once! You need another "const
". Where should it go? The error message comes to the rescue again: it complains about the this
argument. Whether or not *this
is considered to be constant is determined by the presence or absence of the const
keyword after the parameter list:
bool HeartbeatManager::Heart::operator<(const HeartbeatManager::Heart&) const
Upvotes: 2
Reputation: 32847
You are taking a const-qualified lvalue reference to the Heart
. The means the function is not mutating the instance passed. Hence they all should be const
qualified.
bool operator==(const Heart& o) const
// ^^^--> typo ^^^^^
{
return ip == o.ip && port == o.port;
}
bool operator<(const Heart& o) const
// ^^^^^
{
return (uint32_t)ip < (uint32_t)o.ip || (ip == o.ip && port < o.port);
}
bool operator>(const Heart& o) const
// ^^^^^
{
return (uint32_t)ip > (uint32_t)o.ip || (ip == o.ip && port > o.port);
}
That being said, your operator<
and operator>
could be simplified using lexicographical comparison provided by std::tie
bool operator< (const Heart& o) const
{
return std::tie(ip, port) < std::tie(o.ip, o.port);
}
bool operator> (const Heart& o) const
{
return std::tie(o.ip, o.port) < std::tie(ip, port);
}
Upvotes: 1
Reputation: 6125
You want to allow your compare operators to be called on a const
object, so replace
bool operator < (const Heart &o) {
with
bool operator < (const Heart &o) const {
and so on.
Also note that you have implemented operator = ()
rather than operator == ()
Upvotes: 1