C++ STL - equivalent of operator function object templates with assignment? - c++

Are there assignment operator objects in C++? Like std::plus, but to do +=? (Likewise minus, multiplies, divides, etc.)
EDIT - Motivation:
I thought it would be preferable to avoid the extra copy by using the function objects (std::plus(), etc.) in the following code.
template<typename Op>
static vector<int>& memberwiseAssignOp(vector<int>& lhs, vector<int> rhs, Op op)
{
size_t const len = rhs.size();
if (len > lhs.size())
{
lhs.resize(len);
}
transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), op);
return lhs;
}
vector<int>& operator+=(vector<int>& lhs, vector<int> rhs)
{
return memberwiseAssignOp(lhs, rhs, plus<int>());
}
vector<int>& operator-=(vector<int>& lhs, vector<int> rhs)
{
return memberwiseAssignOp(lhs, rhs, minus<int>());
}

More generally than just "no, it's not there", there's the simple fact that overloads of assignment operators need to be done as member functions, so it really can't be done. I guess, since what we're dealing with aren't really operators though, it could be done to the extent that a function could be written to receive a non-const reference to an object, and modify the object to which that referred.
I'm not at all sure you'd gain a whole lot from this though. The types for which it made much difference would really be those types for which it was substantially cheaper to modify an existing object than to overwrite an old object with a new value.
At one time (before C++11), that may have been a fair number of types. Since the introduction of rvalue references you can get roughly the same effect (but much more cleanly) by moving from the old object to the new object, and modifying as you see fit along the way.
In theory, there are probably still a few places that wouldn't work out quite as nicely. The obvious example would be an object that (directly) contains a lot of data, so moving still basically works out to copying.

Here is a list of Functional Operations.
As you can see there are no assignment operators.
You could of course just have this functionality yourself like follows:
a = std::plus(a, b);
But this might not be helpful at all.

Related

Using move semantics and perfect forwarding to implement a 'lazy' operator+

I am trying to write a
friend T operator+( lhs, rhs){
};
Now, I would like to avoid construction of temporaries when possible.
For example:
If both lhs and rhs are const T& the operator+ should create a temp copy-constructing from lhs, then temp += rhs; to it and finally return std::move(temp).
If lhs is T&& then I want to directly sum rhs to it as in lhs += rhs; and then return std::move(lhs). This case avoid a copy-construction in (A+B)+C since the output of (A+B) is not needed outside the expression. Notice that we might have to do temp(std::move(lhs)) to have a common code for both Case 1. and Case 2.
Similarly for the other two case when either rhs or both lhs and rhs are T&&.
By writing four overloads I have managed to do this. Now, I have read that it is possible to take advantage of templates and forward to reduce the number of overloads or maybe even write it in just one template function. I am having trouble understanding how.
It seems to be that I need
template<typename R, typename S, typename T>
R operator+(S&& lhs, T&& rhs){
// ...
};
But what I have tried for the content doesn't work.
There is an additional issue that I might have to deal with. If instead of operator+ we need operator- or operator/ the body of the method it not necessarily similar in all the cases. In A/B, if A is T&& we can A /= B. But if B is the one that is T&& then we might need to do B.reciprocal() *= A. So, I think I also need a way to know which case was entered in the template.
Note: My multiplication IS commutative (component-wise multiplication in matrices).
Could you give some comments and ideas on how to approach this problem?
Note to self and to the next reader: A link to some reading on the use of expression templates.
Write a function named sum. sum has 3 overloads: lhs&&, rhs const& and lhs const&, rhs&&, ... -- the ... is important, as it makes it the worst match, removing ambiguity. And finally const& lhs, const& rhs.
Then template<lhs, rhs> auto operator+(lhs&&,rhs&&)->decltype perfect forwards to sum.
Once you get that working we can move on. We can either reimplement it for each operator, or move up a level of abstraction.
You have a mutating binary op (+= etc) and an anti-symmetric transformation (noop for most, inverse for divide -- the binary op for divide is *= btw). Pass those to a dispatcher overloaded like sum.
Use function objects for those two, and rewriting the sum functions to take increase_mat{} and noop{} should be easy.

Does it make sense to use move semantics for operator+ and/or operator+=?

I was wondering in what kind of cases it makes sense to use move semantics when overloading operator+ and/or operator+=. Even though it is explained in this question how one could do this, I can't wrap my head around as to why I'd do it. Let's consider operator+=. If I just pass right hand side by reference and make the appropriate changes on the left hand side object, there are no unnecessary copies anyway. So we come back to the same point: Would move semantics be beneficial in such a case?
Yes and no.
operator+=
Move semantics are not necessarily helpful for operator+= in general, because you are already modifying the left hand side argument (this), so you already have resources to work with most of the times.
Still, as an optimization, it might be worth it. Imagine a std::string implementation whose default constructor does not allocate any memory. Then std::string::operator+=(std::string&&) could simply steal the resources from RHS. Or imagine that the RHS buffer is big enough to hold everything but the LHS is not, then if you can use the RHS buffer you're golden: just swap and prepend.
So, it may be worth it, but you have to study it. Therefore:
T& T::operator+=(T const&): always present
T& T::operator+=(T&&): to enable move semantics when it makes sense
operator+
Here it is always useful (providing we are talking about classes for which move semantics are useful).
The thing is, operator+ produces a temporary (out of the blue) so it generally has to create resources for this temporary. However if it can steal them rather than create them, it's certainly cheaper.
However, you need not provide all overloads:
T operator+(T const&, T const&)
T operator+(T&&, T const&)
T operator+(T const&, T&&)
T operator+(T&&, T&&) (required for disambiguation)
No, you can reuse the same trick that operator= use and create the temporary right in the function signature (by taking one argument by copy). If the type is movable, the move constructor will get called, otherwise it'll be the copy constructor, but since you need the temporary anyway, no loss of performance.
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(T const& left, T right) { right += left; return right; } // commutative
inline T operator+(T left, T&& right) { left += right; return left; } // disambiguation
Not much of a gain (3 instead of 4) but well, I'll take what I can!
Of course, for string, operator+ is not commutative (which is why it is a bad overload), so the actual implementation of the second overload would require a prepend method.
EDIT: following Move semantics and operator overloading it seems that I was a bit over-enthusiastic. Stealing from Ben Voigt's answer, we get:
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(const T& left, T&& right) { right += left; return right; }
On the other hand, this seems to only work for commutative operations; - does not work that way but can probably be adapted, / and % on the other hand...
If you're appending two strings, vectors etc. that you cannot "move", it doesn't make sense. But if you're appending, say linked lists, where appending the list is possibly an O(1) operator, if you're willing to sacrifice the right hand side, then it makes sense.

Is it reasonable to return a pointer from an overloaded arithmetic operator declared in an abstract class?

I have a couple of pure virtual classes, Matrix and Vector. Throughout my code base I try to only create dependencies on them and not their concrete subclasses e.g. SimpleTransformationMatrix44 and SimpleTranslationVector4. The motivation for this is that I can use third party (adapted) classes in place of mine without much trouble.
I would like to overload the arithmetic operators (sourced from here):
T T::operator +(const T& b) const;
T T::operator -(const T& b) const;
T T::operator *(const T& b) const;
I want to declare them in the pure virtual classes so that it is valid to perform the operations on references/pointers to them, the problem being that an abstract class cannot be returned by value. The best solution I can think of is something like this:
std::unique_ptr<T> T::operator +(const T& b) const;
std::unique_ptr<T> T::operator -(const T& b) const;
std::unique_ptr<T> T::operator *(const T& b) const;
Which allows this (without down casts!):
std::unique_ptr<Matrix> exampleFunction(const Matrix& matrix1, const Matrix& matrix2)
{
std::unique_ptr<Matrix> product = matrix1 * matrix2;
return std::move(product);
}
A pointer seems to be the only option in this case since returning a value is invalid and returning a reference is just plain silly.
So I guess my question is: Have I gone off the plot with this idea? If you saw it in some code you were working on would you be thinking WTF to yourself? Is there a better way to achieve this?
First off: Overloading operators is something that applies best to value types. As you have found out, polymorphism doesn't play well with it. If you are willing to walk on crutches, this might help, though:
If you follow the advice of Stackoverflow's operator overloading FAQ, you will implement operator+() as a non-member atop of operator+=(). The latter returns a reference. It's still a problem, because it can only return a base class reference, but as long as you only use it for expressions expecting that, you are fine.
If you then templatize operator+() as DeadMG suggested, you might be able to do what you want:
template<typename T>
T operator+(const T lhs, const T& rhs)
{
lhs += rhs;
return lhs;
}
Note that this would catch any T for which no better-matching operator+() overload can be found. (This might seem like a good idea — until you forget to include a header and this operator catches the x+y, making the code compile, but silently produce wrong results.) So you might want to restrict this.
One way would be to put it into the same namespace as you matrix and vector types. Or you use a static_assert to ensure only types derived from the two are passed in.
Have I gone off the plot with this idea?
Yes. The appropriate solution to this problem is to implement flexibility via template, not inheritance. Inheritance is most definitely not suited to this kind of problem. In addition, it's usual (if not mandated) to have the dimensions of the vector or matrix specified as a template parameter in addition, instead of at run-time.

Eliminating temporaries in operator overloading

Note: as noted by sellibitze I am not up-to-date on rvalues references, therefore the methods I propose contain mistakes, read his anwser to understand which.
I was reading one of Linus' rant yesterday and there is (somewhere) a rant against operator overloading.
The complaint it seems is that if you have an object of type S then:
S a = b + c + d + e;
may involve a lot of temporaries.
In C++03, we have copy elision to prevent this:
S a = ((b + c) + d) + e;
I would hope that the last ... + e is optimized, but I wonder how many temporaries are created with user defined operator+.
Someone in the thread suggested the use of Expression Templates to deal with the issue.
Now, this thread dates back to 2007, but nowadays when we think elimination of temporaries, we think Move.
So I was thinking about the set of overload operators we should write not to eliminate temporaries, but to limit the cost of their construction (stealing resources).
S&& operator+(S&& lhs, S const& rhs) { return lhs += rhs; }
S&& operator+(S const& lhs, S&& rhs) { return rhs += lhs; } // *
S&& operator+(S&& lhs, S&& rhs) { return lhs += rhs; }
Does this set of operator seems sufficient ? Is this generalizable (in your opinion) ?
*: this implementation supposes commutativity, it doesn't work for the infamous string.
If you're thinking about a custom, move-enabled string class, the proper way to exploit every combination of argument value categories is:
S operator+(S const& lhs, S const& rhs);
S operator+(S && lhs, S const& rhs);
S operator+(S const& lhs, S && rhs);
S operator+(S && lhs, S && rhs);
The functions return a prvalue instead of an xvalue. Returning xvalues is usually a very dangerous thing – std::move and std::forward are the obvious exceptions. If you were to return an rvalue reference you'd break code like:
for (char c : my_string + other_string) {
//...
}
This loop behaves (according to 6.5.4/1 in N3092) as if the code is:
auto&& range = my_string + other_string;
This in turn results in a dangling reference. The temporary object's life-time is not extended because your operator+ doesn't return a prvalue. Returning the objects by value is perfectly fine. It'll create temporary objects but these objects are rvalues, so we can steal their resources to make it very effective.
Secondly, your code should also not compile for the same reason this won't compile:
int&& foo(int&& x) { return x; }
Inside the function's body x is an lvalue and you can't initialize the "return value" (in this case the rvalue reference) with an lvalue expression. So, you'd need an explicit cast.
Thirdly, you're missing an const&+const& overload. In case both of your arguments are lvalues, the compiler won't find a usable operator+ in your case.
If you don't want so many overloads, you could also write:
S operator+(S value, S const& x)
{
value += x;
return value;
}
I intentionally didn't write return value+=x; because this operator probably returns an lvalue reference which would have led to copy construction of the return value. With the two lines I wrote the return value will be move constructed from value.
S x = a + b + c + d;
At least this case is very efficient because there is no unnecessary copying involved even if the compiler isn't able to elide the copies – thanks to a move-enabled string class. Actually, with a class like std::string you can exploit its fast swap member function and make it effective in C++03 as well provided you have a reasonably smart compiler (like GCC):
S operator+(S value, S const& x) // pass-by-value to exploit copy elisions
{
S result;
result.swap(value);
result += x;
return result; // NRVO applicable
}
See David Abraham's article Want Speed? Pass by Value. But these simple operators won't be as effective given:
S x = a + (b + (c + d));
Here the left hand side of the operator is always an lvalue. Since operator+ takes its left hand side by value this leads to many copies. The four overloads from above deal perfectly with this example, too.
It's been a while since I read Linus' old rant. If he was complaining about unnecessary copies with respect to std::string, this complaint is no longer valid in C++0x, but it was hardly valid before. You can efficiently concatenate many strings in C++03:
S result = a;
result += b;
result += c;
result += d;
But in C++0x you can also use operator+ and std::move. This will be very efficient, too.
I actually looked at the Git source code and its string management (strbuf.h). It looks well thought through. Except for the detach/attach feature you get the same thing with a move-enabled std::string with the obvious advantage that the resource it automatically managed by the class itself as opposed to the user who needs to remember to call the right functions at the right times (strbuf_init, strbuf_release).

What is the best signature for overloaded arithmetic operators in C++?

I had assumed that the canonical form for operator+, assuming the existence of an overloaded operator+= member function, was like this:
const T operator+(const T& lhs, const T& rhs)
{
return T(lhs) +=rhs;
}
But it was pointed out to me that this would also work:
const T operator+ (T lhs, const T& rhs)
{
return lhs+=rhs;
}
In essence, this form transfers creation of the temporary from the body of the implementation to the function call.
It seems a little awkward to have different types for the two parameters, but is there anything wrong with the second form? Is there a reason to prefer one over the other?
I'm not sure if there is much difference in the generated code for either.
Between these two, I would (personally) prefer the first form since it better conveys the intention. This is with respect to both your reuse of the += operator and the idiom of passing templatized types by const&.
With the edited question, the first form would be preferred. The compiler will more likely optimize the return value (you could verify this by placing a breakpoint in the constructor for T). The first form also takes both parameters as const, which would be more desirable.
Research on the topic of return value optimization, such as this link as a quick example: http://www.cs.cmu.edu/~gilpin/c++/performance.html
I would prefer the first form for readability.
I had to think twice before I saw that the first parameter was being copied in. I was not expecting that. Therefore as both versions are probably just as efficient I would pick them one that is easier to read.
const T operator+(const T& lhs, const T& rhs)
{
return T(lhs)+=rhs;
}
why not this if you want the terseness?
My first thought is that the second version might be infinitessimally faster than the first, because no reference is pushed on the stack as an argument. However, this would be very compiler-dependant, and depends for instance on whether the compiler performs Named Return Value Optimization or not.
Anyway, in case of any doubt, never choose for a very small performance gain that might not even exist and you more than likely won't need -- choose the clearest version, which is the first.
Actually, the second is preferred. As stated in the c++ standard,
3.7.2/2: Automatic storage duration
If a named automatic object has
initialization or a destructor with
side effects, it shall not be
destroyed before the end of its block,
nor shall it be eliminated as an
optimization even if it appears to be
unused, except that a class object or
its copy may be eliminated as
specified in 12.8.
That is, because an unnamed temporary object is created using a copy constructor, the compiler may not use the return value optimization. For the second case, however, the unnamed return value optimization is allowed. Note that if your compiler implements named return value optimization, the best code is
const T operator+(const T& lhs, const T& rhs)
{
T temp(lhs);
temp +=rhs;
return temp;
}
I think that if you inlined them both (I would since they're just forwarding functions, and presumably the operator+=() function is out-of-line), you'd get near indistinguishable code generation. That said, the first is more canonical. The second version is needlessly "cute".