SoQuote:
Originally Posted by C++ standard, section 13.5.2
are all valid overloads.Code:T T::operator+(const T&);
T T::operator+(const T&) const;
T ::operator+(const T&, const T&);
T ::operator+(T, const T&);
Printable View
SoQuote:
Originally Posted by C++ standard, section 13.5.2
are all valid overloads.Code:T T::operator+(const T&);
T T::operator+(const T&) const;
T ::operator+(const T&, const T&);
T ::operator+(T, const T&);
.Quote:
Originally Posted by treuss
The member version is fine. I was reffering to the friend version.
I'm sorry but I'm not quite following your point. What does that operator+= has to do with how the operator+ is defined? :confused:Quote:
Originally Posted by laserlight
I can understand that but you have operator+(const T& lhs, const T& rhs) and not operator+(T lhs, const T& rhs). What I am trying to say is that the 2nd form calls the copy constructor 1 extra time, regardless of how it is implemented.Quote:
Originally Posted by exterminator
EDIT: what happened to your post? :confused:
Gah, where? I cant find any of the posts in this thread containing operator+ as a friend function. If anything the implementation of the member operator+ that dreamfluid doesnt work at all, but that has to do with it being implemented as if it were global (temp is never assigned to *this in any way), yet defined as if it were a member.Quote:
The member version is fine. I was reffering to the friend version.
i.e. operator+= is used to implement operator+Quote:
What does that operator+= has to do with how the operator+ is defined?
Well, one would expect that an operator defined as a global function is also a friend. :)Quote:
Originally Posted by laserlight
And what does that have to do with sending the 1st argument of the operator+ by value? :)Quote:
Originally Posted by laserlight
Yes, it is obvious that the 2nd form (T operator+(T, const T&) ) calls the copy constructor at least twice. On my part, what I'm trying to point out is that in the 1st form (T operator+(const T&, constT&) ) if operator+ is implemented in terms of operator+=, it may be useful to use the copy constructor to create a temporary copy of one of the arguments, and then apply operator+= on that temporary, returning the temporary by value.Quote:
What I am trying to say is that the 2nd form calls the copy constructor 1 extra time, regardless of how it is implemented.
In such a case, the copy constructor would be called twice, i.e. as many times as in the 1st form. If this is the case, then it may well be better to pass one of the arguments by value (i.e. use the 2nd form) and hence not have to explicitly instantiate a temporary.
Now, if indeed the C++ Standard mandates the 1st form (to work with the standard library?) as a convention, then choosing the 2nd form may not be wise; this is why I would like to know where in the standard is this mentioned. googler's post just shows the forms that are legal, but says nothing about convention that may be useful when working with the standard library.
Actually I was composing the post and then got to talking with a colleague.. in the meanwhile quite a few posts got updated and I thought I reconsider... and you quoted me ...anyways.. here it is (with a little changes/additions):Quote:
Originally Posted by PadexArt
I think there is an item by Scott Meyers regarding this as well... what I could make out of it was two things:
1. You would need to only maintain operator+= for your classes where operator+ is implemented in terms of operator+=.
2. There could be a gain in performance owing to RVO.
Here is the thing: (this is operator+ implemented in terms of operator+=)I agree that there is no problem with having overloads as what treuss is trying to do and I also agree what PadexArt says about copy constructions.Code://just need to maintain this function...
template<typename T>
T& operator+=(const T& rhs){
//do stuff..
return *this;
}
//no maintenance required... once += is maintained well
template<typename T>
const T operator+(const T& lhs, const T& rhs){
return T(lhs)+=rhs; //RVO
}
//first argument by value
template<typename T>
const T operator+(T lhs, const T& rhs){ //copy constructor called as well
return lhs+=rhs; //no RVO as the return object is named
}
Well, hope I am up-to-post while I post my post... :)Quote:
PadexArt: What does that operator+= has to do with how the operator+ is defined?
laerlight: i.e. operator+= is used to implement operator+
PadexArt: And what does that have to do with sending the 1st argument of the operator+ by value?
operator+= has nothing to do with how operator+ is implemented... they can be completely independently defined as well... but don't you think that a kind of rework when there is an alternative way that can give you an extra bit of performance and also keep your worries away while maintaining the code that you only need to modify operator+= when you need to.. You can simply leave the operator+ as it is.. I would consider it as an advantage and would try to exploit it.
As far as sending the first argument by value is concerned look at the second version of operator+ that I have quoted above. Even if operator+ is or is not defined in terms of operator+= what happens is the object gets "named" and hence all possibilities of "un-named RVO" are lost. There could be gains on certain compilers due to "named RVO" (I guess VS 7.0 and above compilers do that, I am not sure). In that case (named RVO), both would be equivalent. And the conclusion that we can derive is that however there (while comparing first argument passed as T or const T&) may be no performance boost on such compilers (with both named and unnamed RVO) still you get the advantage related to code maintainance (while implementing operator+ in terms of operator+=)
Hope I have been clear in what I said.. Regards.
The formQuote:
Originally Posted by PadexArt
always has to call some constructor for T in order to generate a temporary local to be returned by the function, even if that constructor is not the copy constructor. Depending on other implementation details of T, it may be adventageous to use the copy constructor. For instance, if all other constructors take a complicated set of initial parameters. In other circumstances, the copy constructor may be "heavier" than other constructors. So it's not as clear cut as you make it out to be, and it may be reasonable to generate a copy of T by passing it by value.Code:T ::operator+(const T& lhs, const T& rhs);
hmm... good point, but my example could not do what yours does since it declares operator+= returning void. It seems that need to revise my thinking a little :)Quote:
There could be a gain in performance owing to RVO.
You should not return void for the operators.. why? Just for the sake of demonstrating this need.. I wrote the following code on Comeau and compiled it..Quote:
Originally Posted by laserlight
The compile error that I get is:Code:#include<ostream>
using namespace std;
class A{
public:
int a;
void operator+=(const A& rhs){
this->a = this->a+rhs.a;
}
explicit A(int i):a(i){}
};
ostream& operator<< (ostream& os, const A& obj){
os << obj.a;
return os;
}
int main(){
A obj1(10);
A obj2(20);
int i=10;
obj1+=obj2;
cout << (i+=2);
cout << (obj1+=obj2);
return 0;
}
Note that this for int does not fail and the overloading should be done along these lines.. ( i.e. no errors for cout << (i+=2); ). Hope this helps. Regards.Code:"ComeauTest.c", line 23: error: no operator "<<" matches these operands
operand types are: std::ostream << void
cout << (obj1+=obj2);
^
1 error detected in the compilation of "ComeauTest.c".
Yeah, it makes sense to keep the behaviour similiar to that of a primitive type with similiar properties.Quote:
Note that this for int does not fail and the overloading should be done along these lines.. ( i.e. no errors for cout << (i+=2); ).