Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-04-07 13:09:46


Anthony Williams wrote:
> "Peter Dimov" <pdimov_at_[hidden]> writes:
>
>> Eric Niebler:
>>
>>> Can you write what the identity function object would look like in C++0x?
>> struct identity
>> {
>> template<class A> A operator()( A && a ) const
>> {
>> return std::forward<A>( a );
>> }
>> };
>>
>> I guess.
>
> No. That will convert lvalues to rvalues.

I don't understand why.

> You also need the lvalue overload in
> order to preserve the reference-ness of lvalues. IIRC, in Andrei
> Alexandrescu's talk at ACCU 2008 he also claimed you need a const-reference
> overload:
>
> struct identity
> {
> template<class A> A operator()( A && a ) const
> {
> return std::move( a );
> }
> template<class A> A& operator()( A & a ) const
> {
> return a;
> }
> template<class A> A const& operator()( A const & a ) const
> {
> return a;
> }
> };
>
> I'm not sure we need the third overload, as the second will deduce A to be
> "const A". Unfortunately, the only compiler I have which handles rvalue
> references says that the first two are ambiguous when given an lvalue.

If I were to write an identity that works today *and* tomorrow, I would
do it like this:

struct identity
{
   // for C++03 compatibility
   template<typename Sig>
   struct result;

   template<typename This, typename Arg>
   struct result<This(Arg)>
   {
     typedef Arg type;
   };

   template<typename Arg>
   Arg &operator()(Arg &arg) const
   {
     return arg;
   }

   template<typename Arg>
   Arg const &operator()(Arg const &arg) const
   {
     return arg;
   }

#if BOOST_HAS_RVALUE_REFS
   template<typename Arg>
   Arg operator()(Arg &&arg) const
   {
     return std::move(arg);
   }
#endif
};

And now in both C++03 and C++0x, I can be sure the following code works:

     int i = 0;
     int const j = 0;

     // rvalue
     result_of<identity(int)>::type k = identity()(1);
     assert( 1 == k );

     // lvalue
     result_of<identity(int &)>::type l = identity()(i);
     assert( &l == &i );

     // const lvalue
     result_of<identity(int const &)>::type m = identity()(j);
     assert( &m == &j );

As Giovanni points out, in C++0x "The values ti are lvalues when the
corresponding type Ti is a reference type, and rvalues otherwise."

So Peter, is this wrong?

-- 
Eric Niebler
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk