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/10/11, leon zadorin <leonleon77@xxxxxxxxx> wrote:
> On 9/9/11, Kevin P. Fleming <kpfleming@xxxxxxxxxx> wrote:
>> On 09/09/2011 08:23 AM, leon zadorin wrote:
>>> Hi everyone.
>>>
>>> Just started looking-into/reading-on c++0x rvalue refs and would like
>>> clarification on the following code being compiled by gcc v 4.6.1 (on
>>> freebsd 8.2 release, amd64):
>>>
>>> #include<iostream>
>>> struct init {};
>>> struct x {
>>>    template<typename InitPolicy>
>>>    void
>>>    init_from(InitPolicy const&  x)
>>>    {
>>>      ::std::cout<<  "by ref\n";
>>>    }
>>>    template<typename InitPolicy>
>>>    void
>>>    init_from(InitPolicy&&  x)
>>>    {
>>>      ::std::cout<<  "by rvalue ref possibly stealing resources held by
>>> x\n";
>>>    }
>>> };
>>>
>>> int
>>> main()
>>> {
>>>    x x1;
>>>    init i;
>>>    x1.init_from(i);
>>>    return 0;
>>> }
>>>
>>> compiled with:
>>> c++ -std=c++0x main.cc
>>> produces:
>>> "by rvalue ref possibly stealing resources held by x"
>>>
>>>  From various experiments, the above 'x1.init_from(i)' binds as
>>> 'x1.init_from<init&>(i)' [as opposed to 'x1.init_from<init>(i)]... but
>>> even if so -- I was wondering how does this correlate with the
>>> following quote from wiki on c++11:
>>> http://en.wikipedia.org/wiki/C%2B%2B0x#Rvalue_references_and_move_constructors
>>> "... A named variable will never be considered to be an rvalue even if
>>> it's declared as such; in order to get an rvalue, the function
>>> template std::move<T>() should be used ..."
>>>
>>> I am most likely missing something simple here (just starting to read
>>> no rval refs...)
>>
>> What you are missing is that the '&&' modifier for an argument to a
>> *template* function has a different meaning than it does for a regular
>> function.
>
> Ah, I think I see :-) Thanks for that :-)
>
> 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)...
>
> ... and then the whole thing is matched for the rvalue version of the
> method.
>
> 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" ?)...
>
> 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); }
>
> 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)...
>
> ... 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...
>
> ... as far as my tired brain can see at the moment, the only thing I
> can do to protect against accidental regression bugs when
> using/refactoring-to template-methods appears to be to define an
> additional non-const ref overload:
>
> template<typename InitPolicy>
> void init_from(InitPolicy &  x) { /* blah blah */ }
>
> at least that way gcc errors-out the compilation with ambiguity
> between the above and the rval overload options...


wait wait -- my bad :-) Just realized something more straight forward
and better indeed:

std::remove_reference<InitPolicy>::type on the arg in "init_from":

#include <type_traits>

...

template<typename InitPolicy>
void
init_from(typename ::std::remove_reference<InitPolicy>::type &&  x)
{
  ::std::cout<<  "by rvalue ref possibly stealing resources held by x\n";
}

...

I think I am getting more comfortable with the whole thing now...

Thanks for your help and sorry for some OT noise :-) :-) :-)

Best regards
Leon Zadorin.


[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