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&)
Related
I am trying to sort a vector of a class, Foo. In my Foo class, I have overriden the < operator. I pass in iterators to the sort function of a vector<Foo> foo_vec like so: sort(foo_vec.begin(), foo_vec.end()), and I have using namespace std;. What could be causing this error?
More details:
The override, in Foo.cpp
bool Foo::operator <(Foo const & b) {
if (cost < b.cost) return true;
else return false;
}
The call, after including the appropriate files:
vector<Foo> children = b.gen(b); // This returns a Foo vector
sort(children.begin(), children.end()); // Gives error.
Error message:
/usr/local/opt/llvm/bin/../include/c++/v1/algorithm:715:71: error: invalid operands to binary expression ('const Foo' and 'const Foo')
bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
std::sort() is internally dereferencing the iterators and passing the Foo objects to a comparator (likely std::less) that is taking the Foo objects by const reference. However, your operator< is not marked as const, so it can't be called on const Foo objects, only on non-const Foo objects. You need to mark it as const (and should anyway, since it does not modify any member data of the Foo objects), eg:
class Foo {
public:
...
bool operator <(Foo const &) const; // <-- note the *trailing* const!
...
};
bool Foo::operator <(Foo const & b) const { // <-- note the *trailing* const!
return (cost < b.cost);
}
I am trying to overload the less than operator '<' in my class as follows:
//header file
class HuffmanNode{
private:
...
...
int frequency;
public:
...
...
bool operator<(const HuffmanNode &rhs); //overload less than operator
};
//cpp file
bool HuffmanNode::operator<(const HuffmanNode &rhs){
return frequency < rhs.frequency;
}
I want to be able to compare the nodes as follows:
bool HuffmanTree::compareNode(const HuffmanNode &a, const HuffmanNode &b){
if (a < b){
return true;
}
else{
return false;
}
}
The problem I'm having is finding a way to compare the two nodes as consts. I get an error saying that my operator overloading method needs to be marked as const but changing the code in the header to
const bool operator<(const HuffmanNode &rhs);
and the cpp file code to
const bool HuffmanNode::operator<(const HuffmanNode &rhs){
return frequency < rhs.frequency;
}
doesn't seem to remove the error.
I have checked out this solution but using the friend keyword didn't seem to work either.
Thanks for any help!
You misunderstand the concept of usage and positioning of the keyword const.
Just to clarify:
const T functionName(something);
means your functionName returns something of the type T and that is a constant.
Now this:
T functionName(something) const;
means your functionName returns something of the type T and that method is not changing anything in the instance and it is safe to use it even with the objects declared as const.
The 2nd option is the one you are looking for.
#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());
}
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 */ }
I implemented a custom TimeStruct class, where I declare < operator as follows
bool operator<(const TimeStruct t2) const;
implementation is as follows.
bool TimeStruct::operator<(const TimeStruct t2) const
{
//do something, I don't include the actual implementation
return true;
}
Then I have another class X where this TimeStruct class is a member, let's call this member field Y. And I am using a vector, and I want to sort this vector on Y field of Class X. Therefore I will need to specify a method which might serve as a basis for the vector's sort method.
Therefore I declared an additional method in X to compare different X's.
bool compareX(const X& x1, const X& x2) const;
and the implementation is as follows:
bool X::compareX(const X& x1, const X& x2) const
{
return (x1.Y.operator<(x2.Y));
}
Unfortunately this code does not compile. I am receiving the following error.
No matching function call for TimeStruct::operator<(const TimeStruct&) const
candidates are : bool TimeStruct::operator<(TimeStruct&) const
I've been scratching my hair for the last hour, can anybody point out what I've been doing wrong.
You need to pass by const reference in your TimeStruct operator:
bool operator<(const TimeStruct& t2) const;
and, according to the error message, you have provided
bool operator<(TimeStruct&) const
There needs to be a const reference specifier in the operator declaration.
Furthermore, you may want to turn operator< from a member function into a friend function.
It's usually best practice.