Assuming:
R& operator+=( R& r, const V& v );
R& operator+=( R& r, V&& v );
R operator+=( R&& r, const V& v ) { r += v; return std::move(r); }
R operator+=( R&& r, V&& v ) { r += std::move(v); return std::move(r); }
we should have:
R operator+( R r, V const& v ) { return std::move(r)+=v; }
R operator+( R r, V && v ) { return std::move(r)+=std::move(v); }
R operator+( V const& v, R r ) { return std::move(r)+=v; }
R operator+( V && v, R r ) { return std::move(r)+=std::move(v); }
where I assume R
is cheap-to-move, while +=
with a V&&
is only marginally more efficient than a V const&
.
Note that the return value of R operator+=( R&& r, ? )
should be a value. I implement it in terms of +=(const&,?)
, then just move into the return value.
This means you have to implement two +=
operators beyond the above boilerplate.
If there is no gain from a moved-from V
we get:
R& operator+=( R& r, const V& v );
R operator+=( R&& r, const V& v ) { r += v; return std::move(r); }
R operator+( R r, V const& v ) { return std::move(r)+=v; }
R operator+( V const& v, R r ) { return std::move(r)+=v; }
3 boilerplate, one actually implemented function.
If you dislike R operator+=( R&& r, const V& v)
we can rewrite this as:
R& operator+=( R& r, const V& v );
R operator+( R r, V const& v ) { return std::move(r+=v); }
R operator+( V const& v, R r ) { return std::move(r+=v); }
and similarly for the V&&
cases if needed:
R& operator+=( R& r, V&& v );
R operator+( R r, V&& v ) { return std::move(r+=std::move(v)); }
R operator+( V&& v, R r ) { return std::move(r+=std::move(v)); }
We make a copy of the R
in the signature of operator+
rather than internally; if we are going to copy it anyhow, may as well do it in the signature.
Want speed? Pass by value. is the technique used to remove the R const&
and R&&
overloads as redundant.