operator== overloading considering non-static member function - c++

I have defined a class like this
using namespace std;
class foo {
public:
typedef std::pair< int, int > index;
bool operator == ( const index &l, const index &r )
{
return (l.first == r.first && l.second == r.second);
}
void bar()
{
index i1;
i1.first = 10;
i1.second = 20;
index i2;
i2.first = 10;
i2.second = 200;
if (i1 == i2)
cout << "equal\n";
}
};
However I get this error in windows
error C2804: binary 'operator ==' has too many parameters
and this error in linux
operator==(const std::pair<int, int>&, const std::pair<int, int>&)’ must take exactly one argument
I found this topic overloading operator== complaining of 'must take exactly one argument' and seems to be a problem with static and non-static functions in a class. However I don't know how to apply this
For example, this is not correct
bool operator == ( const index &r )
{
return (this->first == r.first && this->second == r.second);
}
How can I fix that?

The operator== can be implemented in two ways:
As member function: in this case, the function takes one argument and is invoked on the left operand which is passed as this pointer implicitly to the function.
As non-member function, in which case, the function takes two arguments, left and right operands.
Since you're implementing operator== for std::pair, you cannot implement it as member function (of std::pair). The option you're left with is non-member function.
So implement it outside the class as:
bool operator==(std::pair<int,int> const & l, std::pair<int,int> const & r)
{
return (l.first == r.first && l.second == r.second);
}
But then you don't really need to implement it yourself unless you want to implement it differently. The Standard Library has already provided a generic version of operator== for std::pair which lexicographically compares the values in the pair, like I did above, i.e compare first with first and second with second. If you need to compare them differently, only then provide your own specific definition (non-template version).
The above mentioned points are worth noting as to how to implement operator== when you need it for your defined types.

You need to move operator== out of class foo:
bool operator == ( const foo::index &l, const foo::index &r )
{
return (l.first == r.second && l.second == r.second);
}
class foo {
public:
typedef std::pair< int, int > index;
void bar()
{
index i1;
i1.first = 10;
i1.second = 20;
index i2;
i2.first = 10;
i2.second = 200;
if (i1 == i2)
cout << "equal\n";
}
};
Also note, std::pair has overload operator== already, see: link, you might reconsider if necessary to write your own again.

If you overload the == operator inside a class, it should only take a single parameter so that comparison can be done between the current object and the argument.

You can move that operator out of the class, that way you can take 2 operands. Indeed there is no point of keeping it within the class at this point, since you are only comparing member variables and not the class itself.
Indeed I wont be surprised if pair already defines the operator you write.
Edit : Yup It looks like pair already implements this
Two pair objects are compared equal if the first elements in both objects compare equal to each other and both second elements also compare equal to each other - they all have to match.
p.s. I think you meant
return (l.first == r.first && l.second == r.second);
^^^^^^

Related

'operator<' error while creating an std::pair<A,B>

I already have a workaround for this but would still like to understand the problem.
I have a Multimap
multimap<QPoint,Figure*> mymap;
QPoint is a class from Qt 5.4. Figure* is a pointer to a
class I have concocted myself.
Now I want to add elements to that map.
This sample works fine:
multimap<int,int> test;
test.insert(pair<int,int>(41,43));
As does this one (being said workaround)
std::pair<QPoint,Figure*> p;
p.first = pos;
p.second = sub_fig;
mymap.insert(p);
However, the plain first reflex of
std::pair<QPoint,Figure*> p(pos, sub_fig);
has the compiler at that line state something like:
[..]
scanner.cpp:264:17: required from here
/usr/include/c++/4.9/bits/stl_function.h:371:20: error: no match for
‘operator<’ (operand types are ‘const QPoint’ and ‘const QPoint’)
{ return __x < __y; }
[..]
followed by the usual five kilometers of stacked STL error messages.
First: The 'types' are not QPoint and QPoint. They are, as
stated above, QPoint and Figure*.
Anyone who can riddle this?
CORRECTION
My work-around does not work either after all. I had forgotten to
de-comment
res.insert(p);
Here is the complete pertinent code:
multimap<QPoint,Figure*> res;
// ...
vector<Figure*> stack = figure->get_above_figure_stack();
for (vector<Figure*>::const_iterator CI2=stack.begin();
CI2!=stack.end();CI2++)
{
// ..
Figure* sub_fig = *CI2;
std::pair<QPoint,Figure*> p;
p.first = pos;
p.second = sub_fig;
res.insert(p); // <- The bad line.
}
multimap needs an ordering relation for the keys, and its default is to use < (in the guise of std::less).
Since QPoint doesn't have an overload of operator<, the compiler is complaining that it doesn't exist.
It's not difficult to provide one:
bool operator< (const QPoint& lhs, const QPoint& rhs)
{
return lhs.x() < rhs.x() || (lhs.x() == rhs.x() && lhs.y() < rhs.y());
}
or
bool lessQPoints (const QPoint& lhs, const QPoint& rhs)
{
return lhs.x() < rhs.x() || (lhs.x() == rhs.x() && lhs.y() < rhs.y());
}
multimap<QPoint, Figure*, lessQPoints> mymap;
The keys in a multimap are ordered by default with std::less which invokes operator< on the key type.
Your key object (QPoint) has no operator< to do the comparison.
You will need to provide your own comparison function using the approprate multimap constructor.

Find equal instance in a c++ set

I'm using a c++ STL set and I want to know if it's present in the set an equivalent instance. To retrive the instance I'm using the find set method. The problem is that it doesn't work. I think the problem is in my comparator object:
bool SetComparator::operator ()( const Point* i1, const Point* i2 ) const {
if ( *i1 == *i2 )
return false;
return true;
}
The operator == is redefined for the class Point in a simple way:
bool Point::operator ==( const Point& p ) const {
if (x == p.x && y == p.y)
return true;
return false;
}
After a debugging I can see that the find method calls operator() but it doesn't find the same instance so the find returns end() but I know that there is an equal object. I think the problem is related to the set internal order. How can I do?
std::set uses partial ordering (i.e. the operator<), so when you pass in an operator that can only decide equality, you break the assumption of the implementation of std::set. Your SetComparator has to behave similar to std::less.
For example std::pair (utility) implements relational operators for two items, e.g. for operator<:
template <class T1, class T2>
bool operator< (const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs) {
return lhs.first<rhs.first || (!(rhs.first<lhs.first) && lhs.second<rhs.second);
}
note that (!(rhs.first<lhs.first) && lhs.second<rhs.second) is a workaround for (rhs.first == lhs.first && lhs.second < rhs.second) using only operator<
If you only want to check for equality maybe using std::set is the wrong decision. If you can hash your objects, you could use a std::unordered_set (C++11 and later).

Vector of structs - not seeing my definition for operator==

I have a class called Something that has two things: a string, and a vector of instructions. In that class, I want to define operator==. However, I get an error when I try to compile:
error: no match for ‘operator==’ in ‘* __first1 == * __first2’
This happened at the line where I am comparing the two vectors in Something using == (since vector has that conveniently defined, I would like to use it).
instruction is as follows:
struct instruction
{
int instr;
int line;
bool operator==(const instruction& rhs)
{
return (instr == rhs.instr) && (line == rhs.line);
}
};
I've searched for a solution to no avail. It seems that vector from the STL is not seeing the operator== I have defined for my struct when it's comparing these elements.
You haven't shown the code that's actually failing, but most likely is a scenario such as this:
int main()
{
vector <instruction> ins;
vector <instruction>::const_iterator itA = /*...*/, itB = /*...*/;
bool b = (*itA == *itB);
}
In this case, the problem is the fact that operator== is not const. Change the declaration as follows:
bool operator==(const instruction& rhs) const
^^^^^^^
Try to add qualifier const to the operator ==.
Also you did not show how the vector is declared and used.
You probably want to make the operator=() method itself const. You do that by adding 'const':
struct instruction
{
int instr;
int line;
bool operator==(const instruction& rhs) const // add const keyword here
{
return (instr == rhs.instr) && (line == rhs.line);
}
};

C++: vector containers and <algorithm> std::find

I created a struct that contains information about variables, namely their name and number
struct var{
string name;
int value;
};
Now, I want to use iterators to update it, using the following function:
void updateVariable(vector<Variable>& vars,Variable& newVar){
vector<Variable>::iterator it = find(vars.begin(), vars.end(), newVar);
if(it == vars.end()){
vars.push_back(newVar);
}
else{
*it = newVar;
}
}
Just to be sure, the error I'm getting is at the line with the call to find(). Any ideas why I'm getting the error? Here is the error:
/usr/include/c++/4.6/bits/stl_algo.h:162:4: error: no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = Variable*, _Container = std::vector<Variable>, __gnu_cxx::__normal_iterator<_Iterator, _Container>::reference = Variable&]() == __val’
Update:
Thank you guys for all the quick help, and the clear answers!
You haven't defined operator == for your var struct. The find() algorithm by default will use operator == to compare the value you provide with the values in the specified range, and return the iterator to the first element which compares equal.
To fix this, just overload operator == for your class. One way to do that is this:
struct var
{
string name;
int value;
};
bool operator == (var const& v1, var const& v2)
{
return (v1.name == v2.name) && (v1.value == v2.value);
}
Make sure you define operator == in the same namespace as your var structure, otherwise ADL (Argument Dependent Lookup) will fail and you will likely get a compiler error.
If you are working with C++11 and you do not want to bother defining an overloaded version of operator ==, you can even use find_if() and pass a lambda as the last argument:
find_if(vars.begin(), vars.end(), [&] (var const& v) {
return (v.name == newVar.name) && (v.value == newVar.value);
});
As GManNickG correctly points out, when you need to compare several members, using std::tie and the overloaded operator == for std::tuple may save you some typing:
auto const tieMembers = [] (const var&) {
return std::tie(v.name, v.value, ...);
};
The above lambda can then be used this way when comparing values v1 and v2 of type var:
return (tieMembers(v1) == tieMembers(v2));
You need to define an overload of operator== for var. This should work.
bool operator==(const var& a, const var& b){
return (a.name == b.name) && (a.value == b.value);
}

C++ how to sort vector<class *> with operator <

i have
class c1{
public:
int number;
c1()
{
number=rand()%10;
}
bool operator < (c1 *w)
{
return number < w->number;
}
};
vector<c1*> vec = { ... }
sort(vec.begin(),vec.end())
why it dosent sort ?
but if we had
bool operator < (c1 w)
{
return number < w.number;
}
and
vector<c1> vec = { ... }
it would have been sorted !
The most straightforward approach is to define a function
bool c1_ptr_less( c1 const *lhs, c1 const *rhs ) {
return lhs->something < rhs->something;
}
std::sort( vec.begin(), vec.end(), & c1_ptr_less );
What I would suggest is a generic functor to take care of all pointer arrays
struct pointer_less {
template< typename T >
bool operator()( T const *lhs, T const *rhs ) const
{ return * lhs < * rhs; }
};
std::sort( vec.begin(), vec.end(), pointer_less() );
Armed with this, define the usual c1::operator< ( const c1 & ) and likewise for other classes.
Generally, best practice is to avoid pointers entirely, including arrays of pointers.
To answer your title question, you can't.
Pointers are built-in types, you cannot override operators where all operands are built-in types.
Luckily, there's an overload of std::sort that allows you to specify a comparison function (or functor) so the operator< isn't used.
bool operator < (c1 *w) compares a c1 to a c1 * - Your sort compares a c1 * to a c1 *
You need to pass a compare function to std::sort:
bool compare_c1 (c1* x, c1* y)
{
return *x < y;
}
std::sort(v.begin(), v.end(), compare_c1);
Or if you are using GCC >= 4.5 or Visual Studio 2010 (I'm do not know sure about Intel compiler) you can use lambdas (they are part of the C++0x standard):
std::sort(v.begin(), v.end(), [] (c1* x, c1* y) { return *x < y; });
Add a external operator< and keep de original one:
bool operator<(c1* a, c1* b) { return *a < *b; }
Now sort will work on the vector.
phimuemue's answer sums it up, I'll just add that, as a workaround, you can create a wrapper class that contains only one member - a pointer to c1, and then overload its operator <. Then you could sort a vector of object of that class.
And in your example, vector<c1*> is sorted. Just not to the
criteria you seem to want: by default, sort uses
std::less<T> as the ordering criteria, and std::less<ci*>
compares the pointers (which is what you'd expect). If you
don't want the default criteria, then you have to pass a third
argument to sort, a predicate defining the ordering you want.
And of course, your member operator<(c1*) will only be called
when you compare a c1 with a ci* (and only if the c1 is an
rvalue). Such operators are very, very rare---normally, both
sides of a < operator should take the same type (and should be
const, since a < operator which modifies the values of the
objects it compares would be surprising, to say the least).