== operator overloading with struct - c++

I'm trying to define an == operator within a struct, like this:
struct names {
string fname;
string lname;
bool operator==(names a, names b) {
return (a.fname == b.lname);
}
};
However, the compiler says:
..\src\trash.cpp:10:33: error: 'bool names::operator==(names, names)' must take exactly one argument
Why is this?

If you overload a binary operator as a member function, then it should only take one argument. The first operand is the object the operator is called on (i.e. *this); the second operand is the single function argument.
struct names {
//...
// better to pass by reference;
// make the function 'const' so it can be used on constant objects
bool operator==(names const & rhs) const {
return this->fname == rhs.lname;
}
};
Alternatively, you can overload it as a non-member function, with two arguments:
bool operator==(names const & lhs, names const & rhs) {
return lhs.fname == rhs.lname;
}
If this needed access to private members (which isn't the case in this example), then it would have to be a friend. You can define friends inside the class definition; in which case the code would look exactly the same as your example, only with friend in front of the function declaration.
(Of course, this isn't a sensible definition of equality since it's not symmetric. Many algorithms will break if you can have a == b but not b==a, as you can with this definition. lhs.fname == rhs.fname && lhs.lname == rhs.lname would make more sense.)

operator== is meant to compare two objects for equality. You have it appearing to compare the first and last names for different objects, presumably to catch duets like George Lazenby and Emma George.
I'd make it a member function of the class and use this for one of the objects:
bool operator== (const names &rhs) const {
return (this->fname == rhs.fname) && (this->lname == rhs.lname);
}

Do:
As member function:
struct names {
string fname;
string lname;
bool operator==(const names& rhs) const { /* Your code */ }
};
or as free function:
bool operator==(const names& lhs, const names& rhs) const { /* Your code */ }

Related

c++ std::set compare function when object is member of the set

I have a set composed of objects; in order to work the operator< must be defined for ordering the objects inside the set. If I define the operator< as a friend function, it works; if I define the operator< as a member function I get the error:
Error C2678 binary '<': no operator found which takes a left-hand >operand of type 'const _Ty' (or there is no acceptable conversion).
I do not understand why the version of operator< implemented as member function does not work/what should be changed about it.
I provide bellow a simplified example of the problem case:
class TestObj
{
private:
int m_a;
public:
TestObj(int a): m_a{a} {}
/* operator < as friend function works */
/*friend bool operator< (const TestObj& t1, const TestObj& t2)
{
return t1.m_a < t2.m_a;
}*/
/* operator < as member function does not work! */
bool operator< (const TestObj& t2)
{
return m_a < t2.m_a;
}
};
void testSetCompare()
{
std::set<TestObj> set1;
set1.insert(10);
set1.insert(20);
}
I do not understand why the version of operator< implemented as member function does not work/what should be changed about it.
You need to make the member function const. Because you declared it as 'non-const' the compiler cannot decide if yout operator willl change *this so your operator cannot be used in a when you have a const TEstObj& what is needed for insert
bool operator< (const TestObj& t2) const
{
return m_a < t2.m_a;
}
will do the job.
Edit: The "No acceptable converson" means that it cannot convert from const TestObj& to TestObj& because it would break the rules of const. (and your operator needs a TestObj&)

no match for ‘operator ==’ in ‘a == b’

#include <iostream>
using namespace std;
class family
{
private:
double weight;
double height;
public:
family(double x,double y);
~family();
double getWeight();
double getHeight();
double setWeight();
double setHeight();
bool operator==(const family &,const family &);
};
bool family::operator ==(const family &a,const family &b)
{
return(a.getWeight() == b.getWeight());
}
family::family(double x, double y)
{
weight = x;
height = y;
}
double family::getWeight()
{
return weight;
}
double family::getHeight()
{
return height;
}
family::~family(){}
int main()
{
family a(70.0,175.2);
family b(68.5,178.2);
if(a==b)
cout << "A is bigger than B" << endl;
else
cout << "A is smaller than B" << endl;
return 0;
}
I want to use method for overloading equal operator.
However, I have an error message
"no match for ‘operator ==’ in ‘a == b’"
Why this error message come up ?
Furthermore, I want to know why there is reference symbol "&" in (const family &,const family &).
Please, give me some advice for modifying my code b.b.
Why this error message come up ?
If you implement a binary operator as a member function, it only receives the right-hand side as an argument, the left-hand side is the calling object. If you write:
a == b
the compiler looks for a function that meets either:
(return type) (type of lhs)::operator==( (type of rhs));
or
(return type) operator==( (type of lhs), (type of rhs) );
Note: (return type) could be anything, though normally you'd want to return bool here. It doesn't affect what the compiler looks for when making the function call.
Your function signature instead is:
(return type) (type: family)::operator==( (type: family), (type: family) );
This is expecting three arguments (one implied)!
Furthermore, I want to know why there is reference symbol "&" in (const family &,const family &).
const family & is the type of argument the function accepts. It receives objects of family type by reference (that is, it uses the original objects rather than making a copy of them), and it promises not to modify them (const). The compiler will enforce this promise. Since the function doesn't need to modify either object, and there's no reason to make a full copy of either, this is exactly the right signature to use. For a non-member function.
For a member function you have to modify it slightly:
class family
{ // ...
bool operator==(
// ...
}
This is fine so far, we don't have to change anything. Your parameter list should only include the right-hand side argument, so:
bool operator==(const family&)
But we're not quite done. Remember how the non-member function uses "const family&" as the parameter type? Somehow we need to mark the calling object as const too. We do this by adding const at the very end:
bool operator==(const family&) const;
(The calling object is already available as though by reference.)
When you go to write the function itself, simply use:
bool family::operator==(const family &rhs) const {
...
}
Then for the body of the function, you can either use the members of the calling object and the rhs directly, or call their relevant functions, like so:
return weight == rhs.weight; // direct member access
or
return getWeight() == rhs.getWeight(); // using functions
If you implement operator== as a member function, it only takes one parameter.
Or in practice, you could implement it as a free function
class family
{
private:
double weight;
double height;
public:
family(double x,double y);
~family();
double getWeight() const;
double getHeight() const;
double setWeight();
double setHeight();
};
bool operator==(const family &a,const family &b)
{
return a.getWeight() == b.getWeight();
}
Update:
AS operator== takes const family objects, you need to make getWight()/getHeight() function const.
You may do the below changes in the code:
double getWeight() const;
.
.
bool operator==(const family &);
.
.
bool family::operator==(const family &b)
{
return weight == b.getWeight();
}
Two possibilities:
(1) If you want to keep your definition same:
declare as non-member and friend:
friend bool operator==(const family &,const family &);
define as:
bool operator ==(const family &a,const family &b)
{
return(a.getWeight() == b.getWeight());
}
(2) Declare as a member (implicit argument is the current object pointed by this):
declare as non-member and friend:
bool operator==(const family &);
define as:
bool family::operator ==(const family &a)
{
return(this->getWeight() == a.getWeight());
}

Using sets and overloading operators in C++

So for class this week I have to use a set to read in the Declaration of Independence and the US Constitution from a .txt file, store them in sets, and overload operator* to find and return the intersection of the two sets.
Reading everything in is not a problem, neither is finding out the intersection in the sets. What I'm having a lot of trouble with is overloading operator*. I keep getting two errors:
no operator "*" matches these operands
and
binary "*":'std::set<_Kty>' does not define this operator or a conversion to a type acceptable to the predefined operator
Here is my code so far:
From main:
Reader r;
std::set<std::string> d, c;
d = r.GetDeclaraton();
c = r.GetConstitution();
Set dec(d), con(c);
Set intersection = dec * con;
The errors are coming from that last line of main.
From Set.h
class Set
{
public:
std::set<std::string> s;
Set(void);
Set(std::set<std::string> set)
{
s = set;
}
~Set(void);
std::set<std::string> operator* (const std::set<std::string> &rhs)
{
std::set<std::string> newset;
std::set<std::string>::iterator rhsiter = rhs.begin(), result;
while (rhsiter != rhs.end())
{
result = s.find(*rhsiter++);
if (result != rhs.end())
{
newset.insert(*result);
}
}
return newset;
}
};
You need
Set operator* (const Set &rhs) const
because this is a binary operator with two Sets as arguments. Your attempt would only work if your Set was deriving std::set.
The return type here is Set. It makes more sense to be the same as the input arguments, and this is also consistent with your usage in main. So in this case you need to modify the definition to construct and return a Set instead of an std::set (or rather you need not because an std::set can be implicitly converted to a Set).
Note also I made operator* a const member function, since it's not modifying its object.
operator* is defined in your custom Set so the left-hand-side argument must be a Set, but in dec.s * con.s you're using .s which accesses the member std::set fields, and there's no operator* defined for a left-hand Set and rhs-hand std::set.
You could change to dec * con.s, but it'd be better to change the operator* rhs argument to a const Set& too, and use rhs.s inside the operator... less confusing!
In my opinion its better to write a global or friend operator. Also, for intersection I would use the & operator, for union the | or + operator while, difference: -...
Why global operators? With global operators you can write an operator for your class even if the left operand is not your class. For example in case of a matrix class you can easily write a global operator that multiplies together a float and a matrix while as a matrix member operator you could write only an operator where your matrix is on the left.
Example:
template <typename T>
inline std::set<T> intersection(const std::set<T>& smaller, const std::set<T>& larger)
{
std::set<T> result;
for (auto it=smaller.begin(),eit=smaller.end(); it!=eit; ++it)
{
if (larger.find(*it) != larger.end())
result.insert(*it);
}
return result;
}
template <typename T>
inline std::set<T> operator & (const std::set<T>& a, const std::set<T>& b)
{
if (a.size() < b.size())
return intersection(a, b);
return intersection(b, a);
}
class Set
{
public:
std::set<std::string> s;
Set() {}
Set(std::set<std::string> _s) : s(_s) {}
friend Set operator & (const Set& a, const Set& b)
{
return Set(a.s & b.s);
}
};
int test()
{
std::set<std::string> s, t;
s.insert("aa");
s.insert("bb");
t.insert("bb");
t.insert("cc");
std::set<std::string> u(s & t);
Set ss(s), st(t);
Set result(ss & st);
return 0;
}

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);
}
};

Polymorphism,STL,find and operator==

I ran into a problem.
I have a class A,and a class that inherits from A,lets call it class B.
I have virtual functions.
I want to compare A and B to another class C by operator==.
If i want to have a list of A's,lets say in stl list,
I must use a pointer to A,so it will look like:
list<*A> list;
and also i have: C something
but now,i cant use the function:find(list.begin(),list.end(),something)
because i cant use operator == for pointers(*).
I found a solution but i dont think its the best,so my question is-can i do it better?
iter=list.begin();
for(iter;iter!=list.end();++iter)
{
if((*iter).operator==(something)
return ...
}
Thank you.
You could use find_if, which lets you provide a function to check for equal values.
auto check_something =
[&something](const list<*A>::iterator& iter){return *iter == something; };
find_if(list.begin(),list.end(),check_something)
You can use
if(**iter == something)
if you want to dereference the pointer.
In C++1x, there is also
for(auto ptr : list)
if(*ptr == something)
Nothing says you can't make a global non-member operator == that operates on pointers or combinations of pointers and objects. If you have many types you could template the combination of pointer vs object equality for any type.
Edit to add this tip: Put the comparison in a namespace with your objects and then argument dependent lookup will find it without putting a global T* == T in scope that catches everything:
namespace equals {
struct A {
A(int x) :x(x) { }
bool operator == (const A &other) const {
return other.x == x;
}
int x;
};
template <typename T>
bool operator == (const T *lhs, const T &rhs) {
return *lhs == rhs;
}
template <typename T>
bool operator == (const T &lhs, const T *rhs) {
return lhs == *rhs;
}
}
Now you can do things like:
equals::A b(1), c(1);
if (b == &c) std::cerr << "good!" << std::endl;
You might have a look at boost::indirect_iterator which is designed for just this purpose.
find(
boost::make_indirect_iterator( list.begin() ),
boost::make_indirect_iterator( list.end() ),
something );