home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 32,087 of 33,346   
   =?ISO-8859-15?Q?Daniel_Kr=FCgler?= to All   
   Re: Implicit move of an lvalue   
   03 Apr 12 13:25:08   
   
   From: daniel.kruegler@googlemail.com   
      
   Am 03.04.2012 20:36, schrieb Kaba:   
   > Have a look at the following code:   
   >   
   > class A   
   > {   
   > public:   
   >       A() {}   
   >       A(const A&  that) {}   
   >       A(A&&  that) {}   
   > };   
   >   
   > template   
   > void f(Type&&  that)   
   > {   
   >       A b(std::move(that));   
   > }   
   >   
   > int main()   
   > {   
   >       A a;   
   >       f(a); // Compiles.   
   >   
   >       return 0;   
   > }   
   >   
   > It is my understanding that 'b' gets move-constructed from 'a' in f(a):   
   >   
   >    * 'a' is an lvalue, and so Type = A&  in f(a).   
   >    * By the reference collapsing rules, A&  &&  = A&.   
   >    * Thus the type of 'that' is A&.   
   >    * 'that' is an lvalue, but gets converted to an rvalue by std::move.   
   >    * Therefore, 'b' gets move-constructed from 'a'.   
      
   I agree with these conclusions.   
      
   > Now consider how close this is to the case banned by the standard, that   
   > rvalue references can not bind to lvalue references:   
   >   
   > void g(A&&  a)   
   > {   
   >       A b(std::move(a));   
   > }   
   >   
   > A a;   
   > g(a); // Error.   
   >   
   > This is for a good reason, of course, because we usually have further   
   > use for an lvalue afterwards.   
   >   
   > I am feeling unease about the template moving from an lvalue as   
   > something that might cause potential traps. What do you think of it?   
      
   I tend to disagree. One needs to be aware that the "perfectly   
   forwarding" signature has been introduced for a very specific reason:   
   To forward any argument based on it's value category thus conserving   
   the value category (at least to the level of xvalue vs. lvalue). If   
   you are working with perfect forwarding signatures, you should   
   *always* use std::forward, not std::move. With this rule in mind,   
   there is only little that can go wrong.   
      
   Alternatively, if you don't want to have this effect, I suggest to   
   constrain the function template to the value category you wish to   
   accept. E.g. if f is supposed to accept *only* rvalues, this is easy   
   to realize by imposing   
      
   template   
   typename std::enable_if::value>::type   
   void f(Type&& that)   
   {   
          A b(std::move(that));   
   }   
      
   If we could turn back time, a better solution of this problem could   
   have been to select a different syntax for perfect forwarding, e.g.   
      
   template    
   void f(Type&&& that);   
      
   Alas, it is too late for this design and we have to arrange with the   
   current state.   
      
   HTH & Greetings from Bremen,   
      
   Daniel Krügler   
      
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca