Re: c++0x and rvalue references on gcc 4.6.1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 9 September 2011 15:28, leon zadorin wrote:
>
> If I understand it correctly -- it would appear that, following a
> general template typename resolution from the function argument, the
> "i" is firstly seen as a reference type (lvalue) of typename "init &"
> (when resolving the "InitPolicy" typename)...

Yes, right so far.

> ... and then the whole thing is matched for the rvalue version of the method.

No.

You call init_from with a non-const lvalue.

There is no rvalue involved.  The template parameter InitPolicy is
deduced as "x&" and the rules of reference collapsing (you can't have
a reference to a reference) mean that the parameter of type
"InitPolicy&&" becomes simply "x&" i.e. an lvalue reference.

So the viable overloads are:

init_from<x>(const x&);
init_from<x&>(x&);

The second one is a better match for a non-const lvalue.



> So it's not the named variable that is being seen as 'rvalue' but
> rather the variable's lvalue (thereby not being in conflict with the
> quote I posted earlier of "named variable never being allowed to be
> considered as an rvalue" ?)...

Nothing is seen as an rvalue.

> This, consequently, appears to act as an implicit ::std::forward
> functionality where ref is converted to rvalue ref:
>
>  template<typename _Tp>
>    inline _Tp&&
>    forward(typename std::remove_reference<_Tp>::type& __t)
>    { return static_cast<_Tp&&>(__t); }

No, there is no implicit forwarding.  lvalues cannot be implicitly
converted to rvalues, that would be dangerous.

> Naturally, by removing the "template-ness" of the "init_from" method
> (i.e. specifying 'init' type explicitly in formal argument
> declaration) -- a completely *opposite* behavior is produced (a "const
> ref" overload of the init_from is chosen by the compiler)...

Because then you have

init_from(const x&);
init_from(x&&);

This time there is no reference collapsing, so the second overload is
not viable, and only the first can be called.  This is not the
opposite, because in both cases an lvalue overload was chosen, you're
just  confused by the presence of && in the function template
signature, but as Kevin said, && on the parameter of a function
template does not mean it can only be called with rvalues.

> ... so I guess if one is trying to generalize "move" semantics in a
> given class by templatizing the explicit argument type into a more
> policy-based approach (from what could have once been a regular,
> non-template method) -- then one has to be extra careful as the
> protection against the "client code" (i.e. the one which calls on
> "init_from") accidentally causing a bug is somewhat reduced...

No, you just be sure to use std::forward.

void doSomethingElse(const x& xx)
{
   ::std::cout << "by lvalue ref\n";
}

void doSomethingElse(x&& xx)
{
   ::std::cout << "by rvalue ref\n";
}


template <typename InitPolicy>
 void
 init_from(InitPolicy && x)
 {
   doSomethingElse( std::forward<InitPolicy>(x) );
 }

When called with an lvalue, InitPolicy will be "x&" and so
"std::forward<x&>(x)" forwards an lvalue, so calls
doSomethingElse(const x&)

When called with an rvalue, InitPolicy will be "x" and so
"std::forward<x>(x)" forwards an rvalue, so calls doSomethingElse(x&&)



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux