Maybe we're talking past each other. I have 3 overload set variants in mind:
(A) T operator?(T, T);
(B) T operator?(T const &, T const &); ... T operator?(T&&, T&&);
(C) T operator?(T const &, T const &); ... T&& operator?(T&&, T&&);
AFAICT, neither (A) nor (B) have any safety issues. Oh, but now I see the problem with (C): T&&'s are implicitly convertible to T&'s...that's what I was missing before. Sorry for being dense.
So if you do
T& a = b + c;
This succeeds in VS2012 with all (no compile or runtime problems, oddly VS2012 extends the lifetime of ref returned by C to be valid), and fails with all in gcc 4.7.2 (compiler error) :P
invalid initialization of non-const reference of type 'T&' from type 'T&&'
Yep, this is what happens in gcc for me.
I swear I just tried a T& y = static_cast
(x) on gcc and finding it compiled fine.
This gave a compiler error for me.
Now you can ask the same question with T const& instead...
Compile succeeds, with only two operands the called overload returns a T, not T&& so there's no problems. If you had: const T& r = a + b + c; (A) and (B) are perfectly safe, but (C) will have runtime issues. Same goes for: T&& a = b + c; T&& r = a + b + c; First line doesn't have any problems with (A), (B), or (C) because of which overload is used. The second line (A) and (B) have no problems but (C) will have runtime issues. Of course, (C) will have a few extra temporaries created (which may or may not be optimized away). The question originally posed is do we: 1. Ignore this problem with (C) to get better performance and just document the problem? 2. Implement (B) to take advantage of move semantics with no internal problems, albeit with a few temporaries being created (if they aren't optimized away by the compiler)? 3. Implement a user-accessible macro switch to let the user decide globally As Jeff said, (3) is ugly especially when linking different codes together, but does provide the most options to the user. (2) isn't necessarily the most efficient but is completely safe. It may also end up being just as efficient as (1) if compilers support the optimization to remove unnecessary temporaries. Daniel's argument is that the problems which occur with (C) are typically a result of user error, and (C) in general guarantees the least amount of temporaries being used. Are there any cases where the problems described above with (C) would be a result of intended behavior with no acceptable work-around? Hopefully we're on the same page now.