std::identity

std::identity

Post by David Krau » Fri, 14 May 2010 21:04:59


There are many uses for std::identity besides as a helper for
std::move. I'm surprised just now to see that it was removed between
N3035 and the FCD.

Can it be moved to <utility>? I imagine there's already a fair amount
of C++0x code out there which depends on it, and likely the popular
implementations haven't yet removed it so the impact is yet unknown.
 
 
 

std::identity

Post by lit » Sun, 16 May 2010 00:47:24


I would also vote to bring it back, if it's really removed. It's one of the
most basic *and* (imho) useful metafunction and it's missing? That would be
odd.

 
 
 

std::identity

Post by 3D?ISO-885 » Thu, 03 Jun 2010 22:54:30

On May 14, 11:47 pm, "Johannes Schaub (litb)" < XXXX@XXXXX.COM >


he
be

I agree that the functionality of such a metafunction is both
fundamental
and useful. One of the severest problems with std::identity is due to
the
same problem as with the pre-standard hash containers that required
a renaming of the finally standardized unordered associative
containers. The original pre-standard definition of identity contains
the member function:

const T& operator()(const T&) const;

see e.g.
http://www.yqcomputer.com/

and many library implementations provide this. Unfortunately this
member causes to make some important specializations ill-formed,
e.g. std::identity<void>. Removing this member again would break
code that exists since decades. My personal favorite solution
of this problem would be to add such a meta function with a
different name, e.g. identity_of. But doing this is a pure library
addition and could be done in a future C++ TR.

Greetings from Bremen,

Daniel Kr=FCgler
 
 
 

std::identity

Post by David Krau » Tue, 08 Jun 2010 05:49:53

On Jun 2, 2:54 pm, =?ISO-8859-1?Q?Daniel_Kr=FCgler?=


Interesting.

It sounds like std::identity<T>::operator() is attempting to do the
job of std::forward<T> (second template argument omitted). The
difference is that forward correctly handles all argument types and
doesn't apply conversion functions: it is a better identity than
identity.

Since std::forward has two template arguments, it could safely be
embedded in std::identity to produce a useful functor:

template< class T >
struct identity {
typedef T type;

template< class U > // not instantiated implicitly with class
T &&operator() ( U &&value ) {
return forward<T>( value ); // or just static_cast<T&&>
}
};

Another effect, taking the address of identity::operator() would
require an extra template argument, but I doubt that happens often and
the fix is easy.
 
 
 

std::identity

Post by Daniel Krl » Tue, 08 Jun 2010 11:03:20

n Jun 7, 4:49 am, David Krauss < XXXX@XXXXX.COM > wrote:

This could be done, but I don't consider it as the right solution.

First, the original (pre-standard) meaning of identity is that
of an unary function object with the following definition:

template <class T> struct identity : unary_function<T,T> {
const T& operator()(const T& x) const {
return x;
}
};

This is a consistent definition that fits well into the series of
function objects defined in sub-clause [function.objects]
describing the contents of header <functional>. Notice that
all these function objects already require the type T to satisfy
the ReferentType requirement from the short but nice concept
era of C++0x, so it doesn't seem astonishing that cv void
won't produce a meaningful specialization of this class
template.

Now, when std::forward was introduced, a class template
named identity was added (in n2284 by accepting the
suggested wording of

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html

) to the <utility> header with the definition:

template <class T> struct identity {
typedef T type;
};

as a helper type to solve a syntactic constraint problem that
a user of std::forward should be enforced to provide the
template parameter T explicitly:

template <class T> T&& forward(typename identity<T>::type&& t);

Thus, identity was only introduced to solve a particular syntactic
problem, but the later evolution of this function template
demonstrated, that proper standardese is (and should be) sufficient
to specify std::forward sufficiently without need of a helper type.

To some extend it could have been said that std::identity should
not have been added (at least not with this name), because the
reason to add it was like that of the auto_ptr_ref, namely to ensure
that a requirement was expressed by code instead of by wording
(Note that std::auto_ptr_ref's state has recently been changed to
be "for exposition only").

If we now compare the definition of std::identity from pre-standard
libraries with that from n1856 we recognize that both are intended
for completely different things: According to SGI, std::identity is a
function object, according to n1856 it is a transformation trait and
should better have better been added to the <type_traits> header.

IMO both view points of identity are completely orthogonal and should
be separated, therefore my suggestion to use a different name for
an identity transformation trait.


Sure, but IMO your revised definition of identity has two problems:

1) It deviates from the current way of defining the standard function
objects from <functional>.

2) It does not really ensure that the mapping is a T -> T mapping.
In fact, std::forward allows some T -> U mappings, where T and
U are different (e.g. when U is a base class of T).

Greetings from Bremen,

Daniel Krler


 
 
 

std::identity

Post by David Krau » Wed, 09 Jun 2010 05:16:51

On Jun 2, 2:54 pm, =?ISO-8859-1?Q?Daniel_Kr=FCgler?=


I replied to this several days ago, but it was apparently lost in a
system glitch... or the mods didn't like it.

[ The message included a problematic ill-formed "References:" header;
I've now edited it manually -- mod/jad ]

The const-reference implementation of identity is exactly what
std::forward was introduced to improve.

Furthermore, std::forward is a template of two arguments, so if it
were embedded in class std::identity, the additional argument would
prevent deleterious immediate instantiation.

Therefore, I suggest

template< typename T >
struct identity {
typedef T type;

template< typename U >
T &&operator() ( U &&value )
{ return forward< T >( value ); }
};