std::identity
and reference-to-temporariesSection: 22.2.4 [forward] Status: C++11 Submitter: Alisdair Meredith Opened: 2008-12-11 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [forward].
View all issues with C++11 status.
Discussion:
std::identity
takes an argument of type T const &
and returns a result of T const &
.
Unfortunately, this signature will accept a value of type other than T
that
is convertible-to-T
, and then return a reference to the dead temporary. The
constraint in the concepts version simply protects against returning
reference-to-void
.
Solutions:
i/ Return-by-value, potentially slicing bases and rejecting non-copyable types
ii/ Provide an additional overload:
template< typename T > template operator( U & ) = delete;This seems closer on intent, but moves beyond the original motivation for the operator, which is compatibility with existing (non-standard) implementations.
iii/ Remove the
operator()
overload. This restores the original definition of theidentity
, although now effectively a type_trait rather than part of the perfect forwarding protocol.iv/ Remove
std::identity
completely; its original reason to exist is replaced with theIdentityOf
concept.
My own preference is somewhere between (ii) and (iii) - although I stumbled over the issue with a specific application hoping for resolution (i)!
[ Batavia (2009-05): ]
We dislike options i and iii, and option ii seems like overkill. If we remove it (option iv), implementers can still provide it under a different name.
Move to Open pending wording (from Alisdair) for option iv.
[ 2009-05-23 Alisdair provided wording for option iv. ]
[ 2009-07-20 Alisdair adds: ]
I'm not sure why this issue was not discussed at Frankfurt (or I missed the discussion) but the rationale is now fundamentally flawed. With the removal of concepts,
std::identity
again becomes an important library type so we cannot simply remove it.At that point, we need to pick one of the other suggested resolutions, but have no guidance at the moment.
[ 2009-07-20 Howard adds: ]
I believe the rationale for not addressing this issue in Frankfurt was that it did not address a national body comment.
I also believe that removal of
identity
is still a practical option as my latest reformulation offorward
, which is due to comments suggested at Summit, no longer usesidentity
. :-)template <class T, class U, class = typename enable_if < !is_lvalue_reference<T>::value || is_lvalue_reference<T>::value && is_lvalue_reference<U>::value >::type, class = typename enable_if < is_same<typename remove_all<T>::type, typename remove_all<U>::type>::value >::type> inline T&& forward(U&& t) { return static_cast<T&&>(t); }[ The above code assumes acceptance of 1120 for the definition of
remove_all
. This is just to make the syntax a little more palatable. Without this trait the above is still very implementable. ]Paper with rationale is on the way ... really, I promise this time! ;-)
[ 2009-07-30 Daniel adds: See 823 for an alternative resolution. ]
[ 2009-10 Santa Cruz: ]
Move to Ready. Howard will update proposed wording to reflect current draft.
Proposed resolution:
Strike from 22.2 [utility]:
template <class T> struct identity;
Remove from 22.2.4 [forward]:
template <class T> struct identity { typedef T type; const T& operator()(const T& x) const; };const T& operator()(const T& x) const;
-2- Returns:x