From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32206 invoked by alias); 9 Sep 2011 16:35:19 -0000 Received: (qmail 32190 invoked by uid 22791); 9 Sep 2011 16:35:17 -0000 X-SWARE-Spam-Status: No, hits=-2.5 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW X-Spam-Check-By: sourceware.org Received: from mail-pz0-f50.google.com (HELO mail-pz0-f50.google.com) (209.85.210.50) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 09 Sep 2011 16:35:03 +0000 Received: by pzd13 with SMTP id 13so1465388pzd.9 for ; Fri, 09 Sep 2011 09:35:02 -0700 (PDT) MIME-Version: 1.0 Received: by 10.68.6.70 with SMTP id y6mr772927pby.391.1315586102757; Fri, 09 Sep 2011 09:35:02 -0700 (PDT) Received: by 10.142.90.10 with HTTP; Fri, 9 Sep 2011 09:35:02 -0700 (PDT) In-Reply-To: References: <4E6A1661.1020100@digium.com> Date: Fri, 09 Sep 2011 16:35:00 -0000 Message-ID: Subject: Re: c++0x and rvalue references on gcc 4.6.1 From: Jonathan Wakely To: leon zadorin Cc: gcc-help@gcc.gnu.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gcc-help-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-help-owner@gcc.gnu.org X-SW-Source: 2011-09/txt/msg00090.txt.bz2 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 met= hod. 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(const x&); init_from(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: > > =A0template > =A0 =A0inline _Tp&& > =A0 =A0forward(typename std::remove_reference<_Tp>::type& __t) > =A0 =A0{ 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 void init_from(InitPolicy && x) { doSomethingElse( std::forward(x) ); } When called with an lvalue, InitPolicy will be "x&" and so "std::forward(x)" forwards an lvalue, so calls doSomethingElse(const x&) When called with an rvalue, InitPolicy will be "x" and so "std::forward(x)" forwards an rvalue, so calls doSomethingElse(x&&)