From: daniel.kruegler@googlemail.com   
      
   Am 30.04.2013 21:48, schrieb Daryle Walker:   
   > I've read about people wondering how to do:   
   >   
   > MyClass   
   > {   
   > public:   
   > //...   
   > void swap( MyClass & ) noexcept( /*What goes here?*/ );   
   > //...   
   > };   
   >   
   > The answer depends on the noexcept status of the internal component   
   > types' swapping. You could put calls to "swap" in the expression and   
   > hope that ADL is invoked. It would probably be complicated.   
      
   The best approach for this is IMO a trait is_nothrow_swappable, where   
   you implement this once (I have done this for lvalue-swaps and for   
   heterogeneous any-value-swaps). It is not that hard and can be done   
   without magic.   
      
   > Then I   
   > thought about C-level arrays. C++11 adds a version of "std::swap" for   
   > C-level arrays. Since that will have a noexcept setting based on the   
   > extents-stripped type, we could use that to universally check for   
   > swap:   
   >   
   > noexcept( std::swap(std::declval(),   
   > std::declval()) );   
   >   
   > This assumes that the built-in array specialization of std::swap   
   > calculates its noexcept status accurately (std::swap for built-ins,   
   > ADL for UDTs, etc.). It can even use compiler magic! Mere users   
   > can't   
   > access any of the magic they use (which may be implementation-   
   > dependent),   
   > but we indirectly access it with this trick.   
   >   
   > Is this viable? Is there an easier alternative?   
      
   The approach looks basically fine, yes. You may get into trouble, if the   
   type is one where swap is really defined but is an abstract type (such   
   as a polymorphic swap), because you cannot form an array type of such   
   beasts. Here is an example from my compile-time test suite of my own   
   is_nothrow_swappable trait:   
      
   namespace blub {   
    struct AbstractNoThrow   
    {   
    virtual void swap(AbstractNoThrow&) noexcept = 0;   
    };   
      
    void swap(AbstractNoThrow& a, AbstractNoThrow& b) noexcept   
    {   
    a.swap(b);   
    }   
      
    struct Abstract   
    {   
    virtual void swap(Abstract&) = 0;   
    };   
      
    void swap(Abstract& a, Abstract& b) noexcept(false)   
    {   
    a.swap(b);   
    }   
   }   
      
   static_assert(xstd::is_nothrow_swappable::value,   
   "Error"); // OK   
   static_assert(noexcept(std::swap(std::declval(),   
    std::declval())), "Error");   
   // Error: cannot allocate an object of abstract type   
      
   static_assert(!xstd::is_nothrow_swappable::value,   
   "Error"); // OK   
   static_assert(!noexcept(std::swap(std::declval(),   
    std::declval())), "Error");   
   // Error: cannot allocate an object of abstract type   
      
   But except from such special cases your approach has been the shortest   
   version I have seen so far.   
      
   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)   
|