Search code examples
c++stlswap

how to provide a swap function for my class?


What is the proper way to enable my swap in STL algorithms?

1) Member swap. Does std::swap use SFINAE trick to use the member swap.

2) Free standing swap in the same namespace.

3) Partial specialization of std::swap.

4) All of the above.

Thank you.

EDIT: Looks like I didn't word my question clearly. Basically, I have a template class and I need STL algos to use the (efficient) swap method I wrote for that class.


Solution

    1. is the proper use of swap. Write it this way when you write "library" code and want to enable ADL (argument-dependent lookup) on swap. Also, this has nothing to do with SFINAE.
    // some algorithm in your code
    template<class T>
    void foo(T& lhs, T& rhs) {
        using std::swap; // enable 'std::swap' to be found
                        // if no other 'swap' is found through ADL
        // some code ...
        swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
                        // or falls back on 'std::swap'
        // more code ...
    }
    
    1. Here is the proper way to provide a swap function for your class:
    namespace Foo {
    
    class Bar{}; // dummy
    
    void swap(Bar& lhs, Bar& rhs) {
        // ...
    }
    
    }
    

    If swap is now used as shown in 1), your function will be found. Also, you may make that function a friend if you absolutely need to, or provide a member swap that is called by the free function:

    // version 1
    class Bar{
    public:
        friend void swap(Bar& lhs, Bar& rhs) {
        // ....
        }
    };
    
    // version 2
    class Bar{
    public:
        void swap(Bar& other) {
        // ...
        }
    };
    
    void swap(Bar& lhs, Bar& rhs) {
        lhs.swap(rhs);
    }
    
    ...
    
    1. You mean an explicit specialization. Partial is still something else and also not possible for functions, only structs / classes. As such, since you can't specialize std::swap for template classes, you have to provide a free function in your namespace. Not a bad thing, if I may say so. Now, an explicit specialization is also possible, but generally you do not want to specialize a function template:
    namespace std
    {  // only allowed to extend namespace std with specializations
    
    template<> // specialization
    void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
        // ...
    }
    
    }
    
    1. No, as 1) is distinct from 2) and 3). Also, having both 2) and 3) will lead to always having 2) picked, because it fits better.