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,269 of 33,346   
   =?ISO-8859-1?Q?Daniel_Kr=FCgler?= to All   
   Re: Conditionally defining copy and move   
   09 May 12 17:25:03   
   
   From: daniel.kruegler@googlemail.com   
      
   Am 10.05.2012 00:05, schrieb Andy Lutomirski:   
   > I have a class template that should be, depending on its parameters,   
   > nontrivially copyable, trivially copyable, or not copyable.  It looks   
   > like this:   
   >   
   > template   
   > struct A   
   > {   
   > 	A(const A&) { body here }   
   >   
   > 	// Members that contain one instance of each type in Types.   
   > };   
   >   
   > If the body is ill-formed, all is well -- A can't be copied.  If all of   
   > the types are copyable and at least one doesn't have a trivial copy   
   > constructor, all is still well: A is copyable.   
   >   
   > I want A to be trivially copyable, though, if all the types are   
   > trivially copyable.  The best I've come up with is:   
   >   
   > template   
   > struct helper   
   > {   
   > 	// if all types are trivially copyable, then   
   > 	typedef garbage type;   
   > 	// else   
   > 	typedef A  type;   
   > };   
   >   
   > template   
   > struct A   
   > {   
   > 	A(const typename helper::type&) { body here }   
   >   
   > 	// Members that contain one instance of each type in Types.   
   > };   
   >   
   > This works until I add a move constructor.  Then I end up with:   
   >   
   > template   
   > struct A   
   > {   
   > 	A(const typename helper::type&) { body here }   
   > 	A(A&&) { ... }   
   >   
   > 	// Members that contain one instance of each type in Types.   
   > };   
   >   
   > If the "copy" constructor is a real copy constructor (i.e. helper::type   
   > is A), then it works.  If not, though, then this is equivalent to:   
   >   
   >   
   > template   
   > struct A   
   > {   
   > 	A(const garbage&) { body here }   
   > 	A(A&&) { ... }   
   >   
   > 	// Members that contain one instance of each type in Types.   
   > };   
   >   
   > which is not copyable at all.  What I really want is:   
   >   
   > template   
   > struct A   
   > {   
   > 	A(const typename helper::type&) { body here }   
   > 	A(const A&) = default;  // But only sometimes   
   > 	A(A&&) { ... }   
   >   
   > 	// Members that contain one instance of each type in Types.   
   > };   
   >   
   > which is ill-formed if helper::type is A.   
   >   
   >   
   > Any ideas?  The default template argument SFINAE trick doesn't work   
   > because copy constructors can't be templates.   
      
   There was a similar question in a previous thread ("How to conditionally   
   disable a copy constructor?" in this newsgroup, about end of November   
   2011. One approach that works is to use base-classes via CRTP to control   
   this. From my reply this part may be of interest for you:   
      
   #include    
   #include    
   #include    
   #include    
      
   struct no_move_no_copy   
   {   
     no_move_no_copy() = default;   
     no_move_no_copy(const no_move_no_copy&) = delete;   
     no_move_no_copy(no_move_no_copy&&) = delete;   
   };   
      
   template   
   struct copy_move   
   {   
     copy_move() = default;   
      
     copy_move(const copy_move& rhs)   
   noexcept(std::is_nothrow_copy_constructible::value)   
     {   
       static_cast(*this).copy_construct(static_cast(rhs));   
     }   
      
     copy_move(copy_move&& rhs)   
   noexcept(std::is_nothrow_move_constructible::value)   
     {   
       static_cast(*this).move_construct(std::move(static_cast(rhs)));   
     }   
   };   
      
   template   
   struct copy_no_move   
   {   
     copy_no_move() = default;   
      
     copy_no_move(const copy_no_move& rhs)   
   noexcept(std::is_nothrow_copy_constructible::value)   
     {   
       static_cast(*this).copy_construct(static_cast(rhs));   
     }   
   };   
      
   template   
   struct move_no_copy   
   {   
     move_no_copy() = default;   
      
     move_no_copy(move_no_copy&& rhs)   
   noexcept(std::is_nothrow_move_constructible::value)   
     {   
       static_cast(*this).move_construct(std::move(static_cast(rhs)));   
     }   
   };   
      
   template   
   struct select_optional_base :   
     std::conditional<   
       std::is_copy_constructible::value,   
       std::conditional::value,   
                        copy_move,   
                        copy_no_move>,   
       std::conditional::value,   
                        move_no_copy,   
                        no_move_no_copy>   
     >::type   
   {   
   };   
      
   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