[Operators] Update, const-correctness and operator chaining
Hi, I was doing some testing with Daniel Frey/Marc Glisse's proposed 4- overload set for binary operators. For reference, here's the overload set applied to commutative addition: friend T operator +( const T& lhs, const T& rhs) { T nrv(lhs); nrv += rhs; return nrv; } friend T operator +(T&& lhs, const T& rhs) { return std::move(lhs += rhs); } friend T operator +(const T& lhs, T&& rhs) { T nrv(lhs); nrv += boost::move(rhs); return nrv; } friend T operator +(T&& lhs, T&& rhs) { return boost::move(lhs += boost::move(rhs)); } This allows this to be done: val1 + val2 = val3; changing the return type to const T would allow the compiler to catch this, but now doing val1 + val2 + val3 must always use copy semantics instead of move semantics. I can't think of a way which would fix this issue without breaking the use of move semantics. How should we proceed with this? It's obviously bad usage, but the compiler should be able to catch this since it's easy to mistype + as =. Interestingly enough, doing testing with std::string shows the same "problem": std::string str1("hello"), str2(" "), str3("world"); str1 + str2 = str3; I tested this issue with std::string and found it in vs2012, gcc 4.3.2, and mingw/gcc 4.8.0. I don't have access to a compiler which pre-dates C++0x/C++11 so I don't know if this issue has always been present. Compiling with gcc 4.8.0 with - std=c++03 still has the issue.
On 13-07-01 02:42 PM, Andrew Ho wrote:
This allows this to be done:
val1 + val2 = val3;
changing the return type to const T would allow the compiler to catch this, but now doing val1 + val2 + val3 must always use copy semantics instead of move semantics.
Two answers: tell your users not to do a+b=c, or tell authors of value type to mark a rvalue overload of operator= "=delete", like: string & operator=(string &&) && = delete; string & operator=(const string &) && = delete; Nobody does this, I'm guessing, because it's just not a problem in practice. I've personally never seen this mistake in real code, and wouldn't worry too much about it. -- Eric Niebler Boost.org
On 1 July 2013 22:42, Andrew Ho wrote:
This allows this to be done:
val1 + val2 = val3;
changing the return type to const T would allow the compiler to catch this, but now doing val1 + val2 + val3 must always use copy semantics instead of move semantics.
I can't think of a way which would fix this issue without breaking the use of move semantics.
You can put an lvalue ref-qualifier on the assignment operator, to forbid assignment to rvalues. T& operator=(const T&)&; I'm not sure it's really beneficial to do so though.
How should we proceed with this? It's obviously bad usage, but the compiler should be able to catch this since it's easy to mistype + as =.
Interestingly enough, doing testing with std::string shows the same "problem":
std::string str1("hello"), str2(" "), str3("world"); str1 + str2 = str3;
I tested this issue with std::string and found it in vs2012, gcc 4.3.2, and mingw/gcc 4.8.0. I don't have access to a compiler which pre-dates C++0x/C++11 so I don't know if this issue has always been present. Compiling with gcc 4.8.0 with - std=c++03 still has the issue.
The example is correct C++03. I'm not aware of it being a big problem, despite being part of the language forever.
Jonathan Wakely
You can put an lvalue ref-qualifier on the assignment operator, to forbid assignment to rvalues.
T& operator=(const T&)&;
I'm not sure it's really beneficial to do so though.
Ok, so it's the User's prerogative to determine if this is important to them or not, as well as depending on compiler support for N2439 (r-value ref for *this). Other than this rather obscure problem I haven't found any glaring issues with the above set, and I've been using it when applicable. Has anyone else found any outstanding issues with using these overloads? Also, I'm curious as to what kind of regression tests we want for Operators, if any. As far as I can tell there's no regression tests for the current version of Operators. Things which might make good tests: 1. General use case for every class 1a. Single operator call 1b. Chained operators 2. Cases where return-by-rvalue ref is known to fail 2a. T& res = a + b 2b. foreach(char c : custom_str1() + custom_str2()) Is there anything else we would want to test?
participants (3)
-
Andrew Ho
-
Eric Niebler
-
Jonathan Wakely