public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* c++0x and rvalue references on gcc 4.6.1
@ 2011-09-09 13:23 leon zadorin
  2011-09-09 13:36 ` Kevin P. Fleming
  0 siblings, 1 reply; 7+ messages in thread
From: leon zadorin @ 2011-09-09 13:23 UTC (permalink / raw)
  To: gcc-help

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...)

Best regards
Leon Zadorin.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 13:23 c++0x and rvalue references on gcc 4.6.1 leon zadorin
@ 2011-09-09 13:36 ` Kevin P. Fleming
  2011-09-09 14:29   ` leon zadorin
  0 siblings, 1 reply; 7+ messages in thread
From: Kevin P. Fleming @ 2011-09-09 13:36 UTC (permalink / raw)
  To: gcc-help

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.

-- 
Kevin P. Fleming
Digium, Inc. | Director of Software Technologies
Jabber: kfleming@digium.com | SIP: kpfleming@digium.com | Skype: kpfleming
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
Check us out at www.digium.com & www.asterisk.org

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 13:36 ` Kevin P. Fleming
@ 2011-09-09 14:29   ` leon zadorin
  2011-09-09 14:54     ` leon zadorin
  2011-09-09 16:35     ` Jonathan Wakely
  0 siblings, 2 replies; 7+ messages in thread
From: leon zadorin @ 2011-09-09 14:29 UTC (permalink / raw)
  To: gcc-help

On 9/9/11, Kevin P. Fleming <kpfleming@digium.com> 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...

Best regards
Leon Zadorin.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 14:29   ` leon zadorin
@ 2011-09-09 14:54     ` leon zadorin
  2011-09-09 15:01       ` leon zadorin
  2011-09-09 16:35     ` Jonathan Wakely
  1 sibling, 1 reply; 7+ messages in thread
From: leon zadorin @ 2011-09-09 14:54 UTC (permalink / raw)
  To: gcc-help

On 9/10/11, leon zadorin <leonleon77@gmail.com> wrote:
> On 9/9/11, Kevin P. Fleming <kpfleming@digium.com> 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.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 14:54     ` leon zadorin
@ 2011-09-09 15:01       ` leon zadorin
  0 siblings, 0 replies; 7+ messages in thread
From: leon zadorin @ 2011-09-09 15:01 UTC (permalink / raw)
  To: gcc-help

On 9/10/11, leon zadorin <leonleon77@gmail.com> wrote:
> On 9/10/11, leon zadorin <leonleon77@gmail.com> wrote:
>> On 9/9/11, Kevin P. Fleming <kpfleming@digium.com> 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";
> }

cancel that -- that's just stupid of me... back to learning I go...

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 14:29   ` leon zadorin
  2011-09-09 14:54     ` leon zadorin
@ 2011-09-09 16:35     ` Jonathan Wakely
  2011-09-09 22:42       ` leon zadorin
  1 sibling, 1 reply; 7+ messages in thread
From: Jonathan Wakely @ 2011-09-09 16:35 UTC (permalink / raw)
  To: leon zadorin; +Cc: gcc-help

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&&)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: c++0x and rvalue references on gcc 4.6.1
  2011-09-09 16:35     ` Jonathan Wakely
@ 2011-09-09 22:42       ` leon zadorin
  0 siblings, 0 replies; 7+ messages in thread
From: leon zadorin @ 2011-09-09 22:42 UTC (permalink / raw)
  To: gcc-help

On 9/10/11, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> 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.
[...]
>> 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&&);
[...]
>> ... 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&&)
>

Wow -- supercool!!! Thanks so much for this explanation! This is
somewhat OT re gcc, but I have learned a lot... supercool indeed!

Best regards
Leon.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-09-09 22:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-09 13:23 c++0x and rvalue references on gcc 4.6.1 leon zadorin
2011-09-09 13:36 ` Kevin P. Fleming
2011-09-09 14:29   ` leon zadorin
2011-09-09 14:54     ` leon zadorin
2011-09-09 15:01       ` leon zadorin
2011-09-09 16:35     ` Jonathan Wakely
2011-09-09 22:42       ` leon zadorin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).