#include <iostream>
using namespace std;
class Test{
private: int cost{};
public:
Test(int value): cost{value}{}
int GetCost() const{return cost;}
bool operator >(const Test& rhs) const noexcept {return GetCost() > rhs.GetCost();}
bool operator>=(const Test& rhs) const noexcept {return (*this > rhs) || (*this == rhs;)}
};
bool operator==(const Test& a, const Test& b) noexcept
{
return a.GetCost() == b.GetCost();
}
int main()
{
cout<< (Test{2} >= Test{3});
return 0;
}
I get the following error for the code.
error: no match for ‘operator==’ (operand types are ‘const Test’ and ‘const Test’)
bool operator>=(const Test& rhs) const noexcept {return *this == rhs;}
What is the problem here? Is it not possible to mix member and non-member operator overloads?
You should also overload operator == in Test class.
class Test{
private:
int cost{};
public:
Test(int value): cost{value}{}
int GetCost() const{return cost;}
bool operator==(const Test& rhs) const noexcept {return GetCost() == rhs.GetCost();}
bool operator >(const Test& rhs) const noexcept {return GetCost() > rhs.GetCost();}
bool operator>=(const Test& rhs) const noexcept {return (*this > rhs) || (*this == rhs);}
};
So you can use it in your overloading and member functions like operator>=.
for more work you can do this:
bool operator==(const Test& a, const int& b) noexcept
{
return a.GetCost() == b;
}
And This:
bool operator==(const int& a, const Test& b) noexcept
{
return a == b.GetCost();
}
By doing so you can even use == as follows:
cout<< (Test{3} == 3);
cout<< (2 == Test{3});
Related
I was working on Circle class that is a child of Shape class and I have some tests that I have to pass that requires me to do some casting
class Shape {
friend bool operator == (const Shape& lhs, const Shape& rhs) {
return (lhs._x == rhs._x) && (lhs._y == rhs._y);}
friend istream& operator >> (istream& lhs, Shape& rhs) {
return lhs >> rhs._x >> rhs._y;}
friend ostream& operator << (ostream& lhs, const Shape& rhs) {
return lhs << rhs._x << " " << rhs._y;}
...
class Circle: public Shape {
friend bool operator == (const Circle& lhs, const Circle& rhs) {
return (lhs._radius == rhs. _radius) && static_cast<Shape>(lhs) == rhs;} // this line
...
How it's different if I did it this way? What's better?
class Circle: public Shape {
friend bool operator == (const Circle& lhs, const Circle& rhs) {
return (lhs._radius == rhs. _radius) && static_cast<const Shape&>(lhs) == rhs;}
I am trying to use std::find with two different types but providing the necessary boolean operators.
class FooDetails
{
public:
FooDetails(int size = 5)
: m_size(size) { /* empty */ }
bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
int m_size;
};
class Foo
{
public:
Foo(int size)
: m_details(size) { /* empty */}
bool operator==(const Foo& other) const { return m_details == other.m_details; }
bool operator==(const FooDetails& other) const {return m_details == other; }
bool operator<(const Foo& other) const { return m_details < other.m_details; }
bool operator<(const FooDetails& other) const { return m_details < other; }
FooDetails m_details;
};
bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }
int main() {
std::vector<Foo> haystack = { FooDetails(5), FooDetails(6), FooDetails(7) };
FooDetails needle(6);
std::find(haystack.begin(), haystack.end(), needle);
return 0;
}
Since std::find uses operator== I would expect this to work, since all necessary functions are provided. However this does not compile. Why is that and how do I fix it?
I know I could use std::find_if, but I assume that's a bit slower and even if it's not I'd like to know why std::find doesn't work.
I've changed your code to this:
#include <algorithm>
class FooDetails
{
public:
FooDetails(int size = 5)
: m_size(size) { /* empty */ }
bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
int m_size;
};
class Foo
{
public:
Foo(int size)
: m_details(size) { /* empty */}
FooDetails m_details;
};
bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }
int main() {
std::vector<Foo> haystack = { Foo(5), Foo(6), Foo(7) };
FooDetails needle(6);
std::find(haystack.begin(), haystack.end(), needle);
return 0;
}
And it successfully compiles. Your original version contains two errors:
You try to create std::vector<Foo> initialising it with std::initialization_list<FooDetails>.
You have provided too many comparison operators: both free versions and members of the Foo struct. So during lookup compiler complains that it doesn't know which one of them to choose. You should leave only one of them.
You have no such constructor in Foo class which constructs it from FooDetails. You need to define the following and your code will work:
Foo(const FooDetails& d) : m_details(d) {}
class my_bool {
private:
bool value;
public:
my_bool(bool value) : value(value) {}
explicit operator bool() { return value };
friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2);
friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
};
void main(){
my_bool a = true;
bool b = false;
if(a == b){
// do something
}
if(a && b){
// do something
}
}
I have just created a similar topic regarding my problem over here binary operator overloading; implicit type conversion . It can be deleted I guess because it is not explicit enough about the problem I am encountering.
Why is that operator== works fine and operator&& causes ambiguities? How do I solve this problem? I can surely write down two more overloads of operator&& (bool, my_bool), (my_bool, bool). That is a messy solution though
The builtin operator&& is a context in which expressions are contextually converted to bool. Other such contexts include for example the condition of if, for, while and the conditional operator ?.
Quoting N4296, §4/4 (the latest publicly available draft before C++14):
Certain language constructs require that an expression be converted to a Boolean value. An expression e
appearing in such a context is said to be contextually converted to bool and is well-formed if and only if the
declaration bool t(e); is well-formed, for some invented temporary variable t (8.5).
Basically, this means that there is an "impicit explicit conversion to bool" in these contexts. Or, to illustrate this further, you can think of the following two lines being one and the same:
a && b
static_cast<bool>(a) && static_cast<bool>(b)
Therefore, the compiler must consider the explicit operator bool() when doing overload resolution for operator&&, but has to ignore it when doing overload resolution for operator== (since that operator does not force a "bool context" .. you can also compare numbers, strings, ...).
The solution in your case is IMO to get rid of the operator&&(const my_bool&, const my_bool&) all together. After all, it does not produce a more meaningful behavior than what would be possible by relying on the builtin operator&&(bool, bool). Establishing a second "boolean context" just isn't something the language was designed for (see below).
If you want to keep this operator, say for some side effects, then I see these choices:
Be explicit at the call site. That is:
if (static_cast<my_bool>(a) && static_cast<my_bool>(b)) { /* ... */ }
Be explicit at the definition site: Provide additional definitions for operator&&(my_bool const &, bool), operator&&(bool, my_bool const &). These then should rule out both operator&&(my_bool const &, my_bool const &) as well as operator&&(bool, bool) because the later are less specific. Adding these definitions to your class should mitigate the issue:
friend my_bool operator&&(const my_bool & lhs, bool rhs) {
// Delegate to operator&&(const my_bool &, const my_bool &)
return lhs && my_bool(rhs);
}
friend my_bool operator&&(bool lhs, const my_bool & rhs) {
// Delegate to operator&&(const my_bool &, const my_bool &)
return my_bool(lhs) && rhs;
}
Turns out one can "establish a boolean context", using CRTP:
#include <iostream>
using namespace std;
template<typename T>
struct bool_context {
friend T operator&&(T const & lhs, bool rhs) {
return lhs && T(rhs);
}
friend T operator&&(bool lhs, T const & rhs) {
return T(lhs) && rhs;
}
friend T operator||(T const & lhs, bool rhs) {
return lhs || T(rhs);
}
friend T operator||(bool lhs, T const & rhs) {
return T(lhs) || rhs;
}
};
struct my_bool : bool_context<my_bool> {
bool value;
my_bool(bool v) : value(v) {}
explicit operator bool() { return value; };
friend my_bool operator&&(my_bool const & lhs, my_bool const & rhs) {
cout << "my_bool::operator&&" << endl;
return lhs.value && rhs.value;
}
friend my_bool operator||(my_bool const & lhs, my_bool const & rhs) {
cout << "my_bool::operator||" << endl;
return lhs.value || rhs.value;
}
};
int main(int, char**) {
my_bool a = true;
bool b = false;
cout << "a && b => "; a && b; // my_bool::operator&&
cout << "b && a => "; b && a; // my_bool::operator&&
cout << "a && a => "; a && a; // my_bool::operator&&
cout << "b && b => "; b && b; cout << endl;
cout << "a || b => "; a || b; // my_bool::operator||
cout << "b || a => "; b || a; // my_bool::operator||
cout << "a || a => "; a || a; // my_bool::operator||
cout << "b || b => "; b || b; cout << endl;
return 0;
}
(Ideone)
My first thought on this is that the arguments to the compiler's built-in operator&& are (bool, bool), so my_bool's explicit bool operator can be invoked - since you are in effect, requesting an explicit conversion.
However, I can't find any reference in the standard as to whether a variable appearing on the right hand side of && should invoke an explicit conversion to bool.
Here's the complete error output from apple clang (once the source code above is fixed):
./nod.cpp:45:10: error: use of overloaded operator '&&' is ambiguous (with operand types 'my_bool' and 'bool')
if(a && b){
~ ^ ~
./nod.cpp:33:20: note: candidate function
friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
^
./nod.cpp:45:10: note: built-in candidate operator&&(_Bool, _Bool)
if(a && b){
^
1 error generated.
So how do I fix it?
Remove the user-defined && operator.
class my_bool {
private:
bool value;
public:
my_bool(bool value) : value(value) {}
explicit operator bool() { return value; }
friend my_bool operator==(const my_bool & instance_1, const my_bool & instance_2);
// friend my_bool operator&&(const my_bool & instance_1, const my_bool & instance_2);
};
int main(){
my_bool a = true;
bool b = false;
if(a == b){
// do something
}
if(a && b){
// do something
}
}
The code bellow works in the same manner for both == and &&.
The class equality is triggered only when are of the same type.
#include <stdio.h>
class my_bool {
private:
bool v{false};
public:
my_bool() : v(v) {};
operator bool (){return v;}
friend bool operator==(const my_bool a, my_bool b){
printf("operator==\n");return a.v==b;
}
friend bool operator&&(const my_bool a, my_bool b){
printf("operator&&\n");return a.v&&b;
}
};
int main(int argc, char **argv)
{ printf("Starting\n");
bool a=true,b=true;
my_bool A{},B{},R{};
a==b;a&&b;
a==A;a&&A;
A==b;A&&b;
A==B;A&&B;
}
I get the following error in Eclipse when trying to compile (c++)
../CardDeck.cpp:17:22: error: passing ‘const CardDeck’ as ‘this’ argument of ‘int CardDeck::size()’ discards qualifiers [-fpermissive]
if I change int size() method to int size() const the error msg is gone and its compiled. I dont know why ?
the .H file is the following :
#include "Card.h"
#include <vector>
using namespace std;
class CardDeck{
private:
vector<Card*> deck;
public:
int size();
CardDeck();
CardDeck(const CardDeck& rhs);
CardDeck& operator=(const CardDeck& rhs);
Card& draw();
Card& top();
bool isEmpty();
void clear();
int value();
CardDeck& operator+=(const CardDeck& rhs); /// not sure if to return ref
CardDeck& operator+(const CardDeck& rhs);
friend CardDeck& operator*(unsigned int num,CardDeck& rhs);
friend CardDeck& operator*(CardDeck& lhs,unsigned int num);
bool operator<=(const CardDeck& rhs );
bool operator>=(const CardDeck& rhs);
bool operator<(const CardDeck& rhs);
bool operator>(const CardDeck& rhs);
bool operator==(const CardDeck& rhs);
bool operator!=(const CardDeck& rhs);
Card* operator[](int i);
};
and the C++ file is :
#include "CardDeck.h"
int CardDeck::size() {
return this->deck.size();
}
CardDeck::CardDeck(){};
CardDeck::CardDeck(const CardDeck& rhs){
this->clear();
int i;
for (i=0;i<rhs.size();i++){
Card* current_card = rhs.deck[i];
Card* new_copy = new Card(*current_card);
this->deck.push_back(new_copy);
}
}
Card* CardDeck::operator[](int i) {
return this->deck[i];
}
void CardDeck::clear(){
vector<Card*>::iterator it ;
for(it=this->deck.begin();it != this->deck.end();++it){
Card* temp = *it;
this->deck.erase(it);
delete(temp);
}
}
In your copy constructor CardDeck::CardDeck(const CardDeck& rhs), rhs is a reference to a const CardDeck object.
So rhs.size() will not compile unless size() is explicitly marked as being const. That's what your compiler is telling you.
It's good practice to have your code as const-correct as possible as this prevents errant changes to the member data in a class. Really, isEmpty(), and possibly value() should be marked const too, as should all the overloaded relational operators.
I'm trying to overload these operators:
<, <=, ==, >=, >, and maybe later !=,
in a struct.
It seems that comparing an object of the struct with another object of the same struct is easy, because when overloading the operator for that scenario, the definition is automatically symmetric.
But what if I want to compare my struct FOOD to an int?
This is also easy as long as FOOD comes first, however, what about the scenario when the int comes first? How do I define that without g++ giving me so many "must contain exactly one argument" errors?
I realize that
bool operator> (const int &, const FOOD &) const;
has problems due to the 'more than one argument' thing. I get that.
On all the forums I've search across the interwebs, everyone's solution seems to be using friend, but their difficulties are always in the context of classes, not structs. How is this done for s struct?
struct FOOD {
int foodID;
double price;
bool operator> (const FOOD &) const; //FOOD > FOOD
bool operator>=(const FOOD &) const; //FOOD >= FOOD
bool operator==(const FOOD &) const; //FOOD == FOOD
bool operator<=(const FOOD &) const; //FOOD <= FOOD
bool operator< (const FOOD &) const; //FOOD < FOOD
bool operator> (const int &) const; //FOOD > int
bool operator>=(const int &) const; //FOOD >= int
bool operator==(const int &) const; //FOOD == int
bool operator<=(const int &) const; //FOOD <= int
bool operator< (const int &) const; //FOOD < int
bool operator> (const int &, const FOOD &) const; // int > FOOD
bool operator>=(const int &, const FOOD &) const; // int >= FOOD
bool operator==(const int &, const FOOD &) const; // int == FOOD
bool operator<=(const int &, const FOOD &) const; // int <= FOOD
bool operator< (const int &, const FOOD &) const; // int < FOOD
};
bool FOOD::operator> (const FOOD &f) const {return foodID > f.foodID;}//FOOD > FOOD
bool FOOD::operator>=(const FOOD &f) const {return foodID >= f.foodID;}//FOOD >= FOOD
bool FOOD::operator==(const FOOD &f) const {return foodID == f.foodID;}//FOOD == FOOD
bool FOOD::operator<=(const FOOD &f) const {return foodID <= f.foodID;}//FOOD <= FOOD
bool FOOD::operator< (const FOOD &f) const {return foodID < f.foodID;}//FOOD < FOOD
bool FOOD::operator> (const int &i) const {return foodID > i;} //FOOD > int
bool FOOD::operator>=(const int &i) const {return foodID >= i;} //FOOD >= int
bool FOOD::operator==(const int &i) const {return foodID == i;} //FOOD == int
bool FOOD::operator<=(const int &i) const {return foodID <= i;} //FOOD <= int
bool FOOD::operator< (const int &i) const {return foodID < i;} //FOOD < int
bool FOOD::operator> (const int &i, const FOOD &f) const {return i > f.foodID;}// int > FOOD
bool FOOD::operator>=(const int &i, const FOOD &f) const {return i >= f.foodID;}// int >= FOOD
bool FOOD::operator==(const int &i, const FOOD &f) const {return i == f.foodID;}// int == FOOD
bool FOOD::operator<=(const int &i, const FOOD &f) const {return i <= f.foodID;}// int <= FOOD
bool FOOD::operator< (const int &i, const FOOD &f) const {return i < f.foodID;}// int < FOOD
g++ gives me these errors:
structsTransAndFood.cc:64:45: error: ‘bool FOOD::operator>(const int&, const FOOD&) const’ must take exactly one argument
Define it outside of the FOOD struct:
bool operator> (const int &i, const FOOD &f) {return i > f.foodID;}
Don't forget to remove this wrong declaration from the FOOD struct:
bool operator> (const int &, const FOOD &) const; // <--- remove it
and the corresponding definition:
bool FOOD::operator> (const int &i, const FOOD &f) const {return i > f.foodID;} // <--- remove it
Repeat the same for other operators.
Solution
You claim that you understand "more than one argument thing". However, it turns out that you don't. I don't get why you have troubles understanding what compiler and 2 people here tell you, but here is how the solution would look like:
struct FOOD {
int foodID;
double price;
bool operator> (const FOOD &) const;
bool operator>=(const FOOD &) const;
bool operator==(const FOOD &) const;
bool operator<=(const FOOD &) const;
bool operator< (const FOOD &) const;
bool operator> (const int &) const;
bool operator>=(const int &) const;
bool operator==(const int &) const;
bool operator<=(const int &) const;
bool operator< (const int &) const;
};
bool FOOD::operator> (const FOOD &f) const {return foodID > f.foodID;}
bool FOOD::operator>=(const FOOD &f) const {return foodID >= f.foodID;}
bool FOOD::operator==(const FOOD &f) const {return foodID == f.foodID;}
bool FOOD::operator<=(const FOOD &f) const {return foodID <= f.foodID;}
bool FOOD::operator< (const FOOD &f) const {return foodID < f.foodID;}
bool FOOD::operator> (const int &i) const {return foodID > i;}
bool FOOD::operator>=(const int &i) const {return foodID >= i;}
bool FOOD::operator==(const int &i) const {return foodID == i;}
bool FOOD::operator<=(const int &i) const {return foodID <= i;}
bool FOOD::operator< (const int &i) const {return foodID < i;}
bool operator> (const int &i, const FOOD &f) {return i > f.foodID;}
bool operator>=(const int &i, const FOOD &f) {return i >= f.foodID;}
bool operator==(const int &i, const FOOD &f) {return i == f.foodID;}
bool operator<=(const int &i, const FOOD &f) {return i <= f.foodID;}
bool operator< (const int &i, const FOOD &f) {return i < f.foodID;}
This type of operator
bool operator> (const int &, const FOOD &) const;
cannot be a member. A member function takes one extra, implicit parameter of type FOOD* (possibly cv qualified), so the example above actually takes three arguments. You need to make it a non-member.
I think the easiest approach would be to give your class an explicit int conversion operator
explicit operator int() const { return foodID; }
Also note that all the comparison operators can be expressed in terms of a single one, for instance bool operator< (this technique is used for example in std library associative containers)