
Forwarded on behalf of and request of Andrei Alexandrescu -Howard Begin forwarded message:
On Apr 8, 2008, at 12:12 PM, Eric Niebler wrote:
There is some confusion on the Boost list about the behavior of rvalue references, caused in part by Andrei's ACCU keynote. Can one of you clear up the issue of the proper way to define the "identity" function in C++0x? Thanks. I haven't read through this entire thread, mainly because I don't have any practical applications for identity at the moment. The simplest version I can think of is: template <class T> T identity(T&& t) {return std::forward<T>(t);} // or return static_cast<T&&>(t) Sorry Andrei, I didn't think of this one before your talk. All cv-qualifiers of the argument are deduced into T. If the argument is an lvalue A, T is deduced as A&, and an lvalue is returned. In
If you don't want to return by value in the case of an rvalue, then you could also: template <class T> T&& identity(T&& t) {return t;} For lvalues, this behaves the same as above. For rvalues you now return by rvalue reference instead of by value. If the client catches
Howard Hinnant wrote: this case, forward (or static_cast) is a no-op. If the argument is an rvalue A, T is deduced as A, and an rvalue is returned (by value). In this case forward (or static_cast) "casts" the lvalue t to an rvalue simply for the purpose of efficiently moving a heavy type to return by value. This also reduces the requirements on an rvalue T from CopyConstructible to only MoveConstructible. this rvalue reference by reference, that reference will be dangling:
const A& acr = identity(A()); // acr now points to a destructed A That may or may not be acceptable for the use cases of identity. I have no idea what those use cases are.
The identity function is not to be used per se; it only gauges to what extent a value transports its type information. For example, if identity works properly, min and max should be easy. Inspired by your solution, I tried this with conceptg++:
template <class T, class U> decltype(true ? T() : U()) Min(T&& a, U&& b) { return b < a ? b : a; }
Given that your implementation of identity works, then the above should work as well by always properly depositing the type of the incoming expressions in T and U whether they are lvalues, const lvalues, or rvalues.
However, the implementation above doesn't work due to what I hope is a compiler bug. The calls:
int a, b; int & f = Min(a, b); int g = Min(a + 1, 42);
work, but this won't:
int g = Min(a, 42);
The error message says:
error: operands to ?: have different types int& and int
But ?: should work with int& and int, yielding int (as needed).
Andrei