Overload operator for set of sets - c++

I just build a mini program to understand how this will work because i need this for something a bit more difficult but i can't make this work.
I think i need to define operator overload but i dont know how because they are two objects of set<set<a>>
If you compile you will see a big error where it notice that he can't compare myset == myset2 and i think it will say same for operator != and =
#include <set>
using namespace std;
class a{
private:
int a_;
public:
int get_a() const{ return a_; }
void set_a(int aux){ a_=aux;}
bool operator < (const a& t) const{
return this->get_a() < t.get_a();
}
};
class b{
private:
set<set<a> > b_;
public:
void set_(set<a> aux){ b_.insert(aux); }
//Overload operators?
};
int main(){
b myset;
b myset2;
set<a> subset1;
set<a> subset2;
a myint;
myint.set_a(1);
subset1.insert(myint);
myint.set_a(2);
subset1.insert(myint);
myint.set_a(3);
subset1.insert(myint);
myint.set_a(5);
subset2.insert(myint);
myint.set_a(6);
subset2.insert(myint);
myint.set_a(7);
subset2.insert(myint);
myset.set_(subset1);
myset.set_(subset2);
myset2.set_(subset1);
myset2.set_(subset2);
if(myset == myset2){
cout << "They are equal" << endl;
}
if(myset != myset2){
cout << "They are different" << endl;
}
b myset3;
myset3 = myset2; //Copy one into other
}

In order for your code to work you need to specify following operators (note: they are not created by default)
class a{
private:
int a_;
public:
int get_a() const{ return a_; }
void set_a(int aux){ a_=aux;}
/* needed for set insertion */
bool operator < (const a& other) const {
return this->get_a() < other.get_a();
}
/* needed for set comparison */
bool operator == (const a& other) const {
return this->get_a() == other.get_a();
}
};
class b{
private:
set<set<a> > b_;
public:
void set_(set<a> aux){ b_.insert(aux); }
/* needed, because myset == myset2 is called later in the code */
bool operator == (const b& other) const {
return this->b_ == other.b_;
}
/* needed, because myset != myset2 is called later in the code */
bool operator != (const b& other) const {
return !(*this == other);
}
};
You should also take a look at http://en.cppreference.com/w/cpp/container/set and see what other operators std::set uses internally on its elements.

No operator (except for the default operator=(const T&) and operator=(T&&)) is generated by the compiler by default. You should define them explicitly:
class b{
private:
set<set<a> > b_;
public:
void set_(set<a> aux){ b_.insert(aux); }
//Overload operators?
bool operator==(const b& other) const {
return b_ == other.b_;
}
bool operator!=(const b& other) const {
return b_ != other.b_;
}
};
However, this only does not solve the case. Although comparison operators are already defined for std::set<T>, they only work if there are operators for T. So, in this case, you have to define operator== and operator!= for your a class in the same manner as I showed you with b class.

Related

incorrect function call on overload operator

In the code, why is (10 != i) calling == instead of !=? The other two call !=
#include <iostream>
class Integer
{
int x;
public:
bool
operator== (const Integer &i)
{
std::cout << "==";
return x == i.x;
}
bool
operator!= (const Integer &i)
{
std::cout << "!=";
return x != i.x;
}
Integer (int t = 0) { x = t; }
};
int
main ()
{
Integer i;
std::cout << (i != i) << '\n'; // calls !=
std::cout << (i != 100) << '\n'; // calls !=
std::cout << (10 != i) << '\n'; // calls ==
}
Prior to C++20, you'd need to add two free functions for the comparison where the int is on the left-hand side:
bool operator==(int lhs, const Integer& rhs) {
return rhs == lhs;
}
bool operator!=(int lhs, const Integer& rhs) {
return rhs != lhs;
}
You should also make the member comparison operators const qualified:
class Integer {
public:
//...
bool operator==(const Integer &i) const { // note const
std::cout << "==";
return x == i.x;
}
bool operator!=(const Integer &i) const { // note const
std::cout << "!=";
return x != i.x;
}
//...
};
You could also remove the member operators to simplify things. Now the left-hand side int will be implicitly converted to Integer and then compared with the right-hand side:
class Integer {
int x;
public:
Integer(int t = 0) : x{t} {}
friend bool operator==(const Integer& lhs, const Integer& rhs) {
return rhs.x == lhs.x;
}
friend bool operator!=(const Integer& lhs, const Integer& rhs) {
return !(rhs == lhs);
}
};
Since you've tagged this C++20, you can let operator== do all the work. See Default comparisons. It'll be used for operator!= too.
class Integer {
int x;
public:
bool operator==(const Integer &i) const {
std::cout << "==";
return x == i.x;
}
Integer(int t = 0) : x{t} {}
};
... and it'll correctly show that it used operator== for all your != comparisons (and negated it).
More from Defaulted equality comparison:
A class can define operator== as defaulted, with a return value of bool. This will generate an equality comparison of each base class and member subobject, in their declaration order. Two objects are equal if the values of their base classes and members are equal. The test will short-circuit if an inequality is found in members or base classes earlier in declaration order.
Per the rules for operator==, this will also allow inequality testing
This means that you will in fact get away with the below only since C++20:
class Integer {
int x;
public:
bool operator==(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
or even better, get all the comparison operators for free by defaulting the spaceship operator <=>:
class Integer {
int x;
public:
auto operator<=>(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
There are two new additions to C++20 that made this possible (note that your code doesn't compile in earlier standard versions).
Compiler will attempt to replace a != b with !(a == b) if there is no suitable != for these arguments.
If there is no suitable a == b, compiler will attempt b == a as well.
So, what happens - compiler first notices that it doesn't know how to compare 10 != i, so it tries !(10 == i). There is still no suitable comparison, so it tries !(i == 10) and it can finally be done using your implicit constructor to convert 10 to Integer.
It can be easily verified by adding more info to debug print:
bool
operator== (const Integer &i) const
{
std::cout << x << "==" << i.x << ' ';
return x == i.x;
}
will print 0==10 1 in the last line (see it online).
As noticed in comments, you don't even need operator !=, due to aforementioned behaviour C++20 compiler will automatically convert any such call to operator ==.

Why std::queue requires the element to be copyable?

In the code below std::deque compiles, but std::queue does not:
class A
{
public:
explicit A(int a) : m_a(a)
{
++count;
}
~A()
{
--count;
}
A(A const &) = delete;
A(A && other) : A(other.m_a)
{
other.m_moved = true;
}
A & operator = (const A &) = delete;
A & operator = (A && other)
{
m_a = other.m_a;
other.m_moved = true;
return *this;
}
bool operator == (const A & other) const
{
return m_a == other.m_a;
}
bool operator != (const A & other) const
{
return !operator==(other);
}
bool operator < (const A & other) const
{
return m_a < other.m_a;
}
static int count;
private:
bool m_moved = false;
int m_a;
};
int A::count = 0;
int main()
{
std::deque<A> d;
std::queue q(d);
q.push(A(1));
return 0;
}
but if I make class A copyable by changing A(A const &) = delete; with A(A const &) = default; it starts to compile.
What is the logic behind this? As far as I can see, std::deque is an adapter that does not add some extra functionality.
Elements are copied when you construct queue from deque, but you've deleted copy constructor for deque's value type (A). So you need to move d when constructing queue.
...
int main()
{
std::deque<A> d;
std::queue q(std::move(d)); // added std::move
q.push(A(1));
return 0;
}

Templated operator ==

I have what is essentially class containing a std::map where the values are shared_ptrs wrapping a container which holds different types. Skeleton code follows:
// Just a basic example class
class MyClass {
public:
explicit MyClass(int i) : mI(i) {}
bool operator==(const MyClass& rhs) { return mI == rhs.mI; }
private:
int mI;
};
// A class into which key value pairs can be added where the value
// can be of a different type.
class MultipleTypeMap {
public:
template <typename T>
void AddObject(const std::string& key, const T object) {
auto ptr = make_shared<B<MyClass>>(std::move(object));
mSharedPtrMap.insert(pair<string, shared_ptr<A>>("key", ptr));
}
// ...
private:
class A {
public:
virtual ~A() = default;
};
template<typename T>
class B : public A {
public:
explicit B(const T& t) : item(t) {}
const T item;
};
map<string, shared_ptr<A>> mSharedPtrMap;
};
int main() {
MyClass m(1);
MultipleTypeMap multiMap;
multiMap.AddObject("test", m);
MyClass n(1);
MultipleTypeMap multiMap2;
multiMap2.AddObject("test", n);
if (multiMap == multiMap2) {
cout << "Equal" << endl;
}
return 0;
}
How should a generic == operator of MultipleTypeMap be written so that it compares the contents of mSharedPtrMap by checking that both the lhs and rhs objects have the same number of keys, the same keys and the same objects where same means that the == operator of the keys / objects evaluates to true?
If you type erase (and later on don't know which type you previously stored), then all the functionality must be provided by the base class interface. So, we need a virtual operator== in A that is implemented in each B.
Here is an implementation:
class MultipleTypeMap {
public:
template <typename T>
void AddObject(const std::string& key, T object) {
auto ptr = std::make_unique<B<T>>(std::move(object));
mMap.emplace(key, std::move(ptr));
}
// ...
bool operator==(const MultipleTypeMap& other) const
{
// Sizes must be equal.
if (mMap.size() != other.mMap.size())
return false;
// Sizes are equal, check keys and values in order.
auto itOther = other.mMap.begin();
for (auto it = mMap.begin(); it != mMap.end(); ++it, ++itOther)
{
if (it->first != itOther->first)
return false;
if (*it->second != *itOther->second)
return false;
}
// No differences found.
return true;
}
bool operator!=(const MultipleTypeMap& rhs) const { return !(*this == rhs); }
private:
class A {
public:
virtual ~A() = default;
virtual bool operator==(const A& other) const = 0;
bool operator!=(const A& other) const { return !(*this == other); }
};
template<typename T>
class B : public A
{
public:
explicit B(const T& t) : item(t) {}
bool operator==(const A& other) const override
{
const B<T>* otherB = dynamic_cast<const B<T>*>(&other);
// If the cast fails, types are different.
if (!otherB)
return false;
// Note: The above is probably slow, consider storing (on construction)
// and checking typeids instead.
// Check item equality.
return item == otherB->item;
}
const T item;
};
std::map<std::string, std::unique_ptr<A>> mMap;
};
Demo with tests
Note: I didn't fix every inconsistency in the original code. (Do you want to move or copy-construct your T? Why store const objects when your MyClass comparison operator is not const?)

Chained equal operator overloading

I would like to add an option to make a chained comparison on objects of MyClass. For example:
MyClass one;
MyClass two;
MyClass three;
/*....*/
if (one == two == three){
/*....*/
}
So that if all are equal it will return true, else it will return false.
I currently have this operator overload that works fine when comparing only two instances of MyClass:
bool operator==(const MyClass &other);
I understand that one==two==three is equal to ((one==two)==three) so I guess that should change my operator== to be something like:
MyClass& operator==(const MyClass &other);
But I couldn't manage to understand how to complete this in order to be able to compare more than two instances in a row (chained).
As pointed out in comments, it's not good to break the usual semantics in such a way. The Principle of least Astonishment should be followed as mentioned.
But I couldn't manage to understand how to complete this in order to be able to compare more than two instances in a row (chained).
Not that I think it's really a good idea to do so1, but here's a working solution:
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int x_) : x(x_), isfalse(false) {}
const MyClass& operator==(const MyClass& rhs) const {
if(!isfalse && x == rhs.x) {
return rhs;
}
return FalseInst;
}
operator bool() const {
return !isfalse;
}
private:
int x;
MyClass() : x(), isfalse(true) {}
const bool isfalse;
static MyClass FalseInst;
};
MyClass MyClass::FalseInst;
int main()
{
MyClass one(1);
MyClass two(1);
MyClass three(1);
if(one == two == three) {
cout << "Yay!" << endl;
}
MyClass four(1);
MyClass five(0);
MyClass six(0);
if(!(four == (five == six))) {
cout << "Yay!" << endl;
}
}
Live Demo
1) Note the warning issued by the compiler.
As a purely theoretical problem, here is a way to solve it:
#include <iostream>
using namespace std;
class A {
public:
int x;
A(int x = 0) : x(x) {}
struct Cmp {
const A *ptr;
mutable bool val;
operator bool() const {
return val;
}
const Cmp &operator == (const A &other) const {
return other == *this;
}
};
bool isEqualTo (const A &other) const {
return x == other.x;
}
Cmp operator == (const A &other) const {
return {this, isEqualTo(other)};
}
const Cmp &operator == (const Cmp &other) const {
//other.val = other.val && (*this == *other.ptr).val;
other.val &= other.ptr->isEqualTo(*this);
return other;
}
};
int main() {
cout << (A(10) == A(10) == A(10)) << endl;
cout << (A(10) == A(9) == A(10)) << endl;
return 0;
}

C++ Bool Operator==

I just tried to make a function that compares 2 objects, but it gives me:
Error: bool Duree::operator==(const Duree&, const Duree&) must take exactly one argument
How can I solve this? Thank you.
Duree.h
#ifndef DEF_DUREE
#define DEF_DUREE
class Duree
{
public:
Duree(int heures = 0, int minutes = 0, int secondes = 0);
bool estEgal(Duree const& b) const;
bool operator==(Duree const& a, Duree const& b);
private:
int m_heures;
int m_minutes;
int m_secondes;
};
#endif
Duree.cpp
#include "Duree.h"
Duree::Duree(int heures, int minutes, int secondes) : m_heures(heures), m_minutes(minutes), m_secondes(secondes)
{
}
bool Duree::estEgal(Duree const& b) const
{
return (m_heures == b.m_heures && m_minutes == b.m_minutes && m_secondes == b.m_secondes);
}
bool operator==(Duree const& a, Duree const& b)
{
return a.estEgal(b);
}
Main.cpp
#include <iostream>
#include "Duree.h"
using namespace std;
int main()
{
Duree fisrt(10, 10, 10), second(15, 20);
if (fisrt == second)
cout << "Les durees sont identiques";
else
cout << "Les durees sont differentes";
return 0;
}
Either you declare operator== as a free function with two arguments:
bool operator==(Duree const& a, Duree const& b);
or as a member function with only one argument:
bool Duree::operator==(Duree const& b);
This is because when you do x == y you are comparing only two objects. If you have a member function there's an implicit "this object" (the one you call operator== on) passed, making it 3 arguments instead of 2.
That being said, from the way you wrote the code I'm guessing you just forgot to put friend in front of the operator== declaration, in the class definition.
Probably useful tip: You can use #pragma once, on compilers that support it (basically every "main" compiler), instead of include guards. :)
Change your prototype to bool operator==(Duree const& rhs); or make it a free function out of class Duree.
Always prefer the binary functions to be NON MEMBER (free) functions. Otherwise you can run into problems if you overload the operator with different types. Consider the following contrived code:
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
};
This should work fine for comparing two Foos together. But it has a problem.
Suppose you also want to compare to an int:
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
bool operator==(int other) const { return x == other; }
};
Now you can compare one way but not the other:
Foo a, b;
...
a == b; // ok
a == 123; // ok
123 == a; // ERROR
As member function the object must be on the right hand side.
Simple, move the int-Foo overloads out of the class, and make two versions, Foo==int and int==Foo? (Note, making them friends declared inside the class can accomplish that too, FWIW, but I'm not showing it here.)
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
};
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
So now everything works, right? We have a mix of member and non-member operators.
a == b; // ok
a == 123; // ok
123 == a; // ok
Until Foo starts getting member functions that want to use the operators...
struct Foo {
int x;
bool operator==(Foo const & other) const { return x == other.x; }
void g(int x);
};
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
void Foo::g(int x)
{
Foo f = getOtherFoo();
if (f == x) { // ERROR! cannot find operator==(Foo,int)
//...
}
}
It STILL has a problem! Inside members of of Foo, it cannot see the non-member operators because the member one hides them! g() will not compile since it can't compare Foo to int. Moving all of the operators out will resolve it, since then all of the overloads are in the same scope.
(Remember, name-lookup keeps searching outer scopes UNTIL it finds the fist case of the name it is looking for, and then only considers all the names it finds in that scope. Inside g(), it's scope is in the class, and since it finds one version of the operator inside the class (the wrong one), it never looks outside the class for more overloads. But if they are all outside the class, it'll find them all at the same time.)
struct Foo {
int x;
void g(int x);
};
// NON MEMBER
bool operator==(Foo const & lhs, Foo const & rhs) { return lhsx == rhs.x; }
bool operator==(int other, Foo const& f) { return f.x == other; }
bool operator==(Foo const& f, int other) { return f.x == other; }
void Foo::g(int x)
{
Foo f = getOtherFoo();
if (f == x) { // OK now, finds proper overload
//...
}
}
Now, it compiles in all the cases. That's why they say, "Always prefer to make non-member binary operator overloads." Otherwise you can end up with symmetry and hiding problems.
I'm on the same kind of issue.
Worked by putting operator== with two arguments back in main.cpp before the main() ;)