Here is my code:
#include <iostream>
#include <memory>
#include <vector>
class var {
private:
double value_;
std::shared_ptr<var> left_;
std::shared_ptr<var> right_;
public:
var(const double& v) : value_(v){};
friend var operator+(const var& l, const var& r) {
var result(l.value_ + r.value_);
left_ = std::make_shared<var>(l.value_);
right_ = std::make_shared<var>(r.value_);
return result;
}
friend std::ostream& operator<<(std::ostream& os, const var& var) {
os << var.value_;
return os;
}
};
int main() { var a(1); }
The error I am getting is as follows:
test.cpp: In function ‘var operator+(const var&, const var&)’:
test.cpp:17:9: error: invalid use of non-static data member ‘var::r_’
17 | r_.push_back(std::make_shared<var>(l.value_));
| ^~
test.cpp:10:39: note: declared here
10 | std::vector<std::shared_ptr<var>> r_;
| ^~
I am struggling to understand why I am getting the error in the title.
Is there a workaround?
Your friend var operator+ is not a member of the class.
In order to access data members it should specify the instance.
Therefore change:
left_ = std::make_shared<var>(l.value_);
right_ = std::make_shared<var>(r.value_);
To:
//vvvvvvv---------------------------------------
result.left_ = std::make_shared<var>(l.value_);
result.right_ = std::make_shared<var>(r.value_);
Note:
As commented above by #PeteBecker: in the general arithmetic case a more efficient approach would be to implement operator+= as a member, and then implement operator+ in terms of it (create a copy of the 1st argument, use operator+ to add the 2nd to it and return it).
It is probably not relevant in this specific case, since operator+= doesn't make much sense.
Related
Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).
I try to create a custom class used with std::set. I know I need to provide a custom comparator for it so I overloaded the operator<. But when I try to copy the set with the code set<Edge> a; set<Edge> b = a;,
I get the following error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__functional_base:63:21: Invalid operands to binary expression ('const Edge' and 'const Edge')
class Edge {
public:
Edge(int V, int W, double Weight):v(V),w(W),weight(Weight){}
int other(int vertex){ return v ? w : vertex == w;}
int v,w;
double weight;
friend std::ostream& operator<<(std::ostream& out, const Edge& e)
{
out<<e.v<<' '<<e.w<<' '<<"weight:"<<e.weight<<'\n';
return out;
}
bool operator<(const Edge& other)
{
return weight < other.weight;
}
};
Make
bool operator<(const Edge& other) const
as the comparison operator must be marked const. The keys in a std::set are const, so the operator< is invoked on a const instance, hence must be marked const.
Whats wrong with my code shown below? please somebody throw some light. Thanks for your time !
#include<iostream.h>
using namespace std;
struct mydata{
int mx;
mydata(int x = 0){}
mydata operator+(const mydata& rhs){
mydata temp(rhs);
return temp;
}
operator int() const{ return mx; }
operator double() const{ return mx; }
};
int main(){
mydata d;
mydata r = d + 5; // L1
5 + d; // L2
d + d; // L3
}
First, you haven't stated what the problem is, but presumably you want an operator+ that sums the mx values of two mydata objects:
mydata operator+(const mydata& rhs){
return mydata (mx + rhs.mx);
}
Next, I would suggest making this a non-member function, so that the LHS and RHS get treated in the same way, fixing the problem in L2:
mydata operator+(const mydata& lhs, const mydata& rhs){
return mydata (lhs.mx + rhs.mx);
}
Finally, you will have an ambiguous overload remaining, because the compiler cannot decide whether to use the built-in operator+(int,int) or your own operator+(const mydata&, const mydata&). You can fix this by removing the cast operators int() and double().
See demo here.
The problem (stated the comment) is that compiler doesn't know which + you want to execute:
(double)d + 5
or
(int)d + 5
In order to resolve this ambiguoity, you should point the type conversion, or replace one of these operators by a named function:
operator int() const{ return mx; }
operator double() const{ return mx; }
If you want instead use d + mydata(5) you should write so, because the above variants are more likely to be applied
You could provide a few non-member operator+ to enable operator+ with different data type:
mydata operator+(const mydata& lhs, const mydata& rhs){
return mydata (lhs.mx + rhs.mx);
}
mydata operator+(int mx, const mydata& rhs){
return mydata (rhs.mx+mx);
}
mydata operator+(const mydata& lhs, int mx){
return mydata(lhs.mx+mx);
}
You can't do 5 + d. 5 can not be converted to class object like this. For this you need to get the operator + definition out of the class method. (in my knowledge preferably friend).
Anyone got an idea on how to write an operator for a class that isn't a member function of the class?
Just make it a free function, or a friend function. A good example of this is operator<<:
class X {
public:
int x;
}
ostream& operator<< (ostream& os, const X& x) {
os << x.x;
return os;
}
The benefit of making it a friend function is that you have direct access to private members, whereas a free function must access all members via public methods.
Arithmetic operators, stream operators, et cetera are often not members of a class. However, they may need to be friends in order to access private data members.
I prefer not to use friend and to expose methods that can be used by the operators instead. I believe this to be more in keeping with the Open/closed principle, as I could easily add a subtraction operator without editing the class.
These are handy for unit-testing, too (I can "inject" a std::ostringstream to test the output of print(), for instance).
Here is an example:
#include <iostream>
class Number
{
public:
Number(int j)
:i(j)
{
}
void print(std::ostream& os) const
{
os << i;
}
int value() const
{
return i;
}
private:
int i;
};
std::ostream& operator <<(std::ostream& os, const Number& n)
{
n.print(os);
return os;
}
Number operator +(const Number& n, const Number& o)
{
return Number(n.value() + o.value());
}
int main()
{
Number a(4), b(5), c(a + b);
std::cerr << c << std::endl;
}
Just declare the global function with the operator name:
Point operator+(Point& p, Vector& v) {
return new Point(p.x + q.i, p.y + q.j);
}
Basically, you can take the operator out of the class, and add a parameter to the beginning of the parameter list. In many cases, you will also need to declare the operator function as a friend.
For instance
class Foo
{
Foo operator +( Foo const& other );
};
becomes
class Foo
{
friend Foo operator +( Foo const&, Foo const& );
};
Foo operator +( Foo const& first, Foo const& second );
The friend statement allows the operator to still access any private or protected members needed.
Note that there are some restrictions on which operators can be overloaded in this manner. See this article for such a list.
Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).