What swap is called when using std::swap?

Discussion in 'C++' started by Niels Dekker (no reply address), Jul 19, 2006.

  1. When calling swap as follows (as recommanded in Effective C++, 3rd
    Edition, by Scott Meyers), what swap is chosen to be called?
    using std::swap;
    swap(a, b);

    Suppose there is a global ::swap function provided, whose parameter type
    matches closer to the type of a and b than any of the std::swap
    overloads does. Will this ::swap be called, or is std::swap still
    preferred? I ask this because the compilers I tried disagree! So will
    any of the ::swap functions I defined down below be called in the
    following main()?

    #include <algorithm>
    struct Foo {};

    void swap(int &, int &) {}
    void swap(Foo &, Foo &) {}
    template<typename T> void swap(T*&, T*&) {}

    int main()
    {
    using std::swap;

    int i1, i2;
    swap(i1, i2);

    int *ptr1, *ptr2;
    swap(ptr1, ptr2);

    Foo foo1, foo2;
    swap(foo1, foo2);

    Foo *foo_ptr1, *foo_ptr2;
    swap(foo_ptr1, foo_ptr2);
    }

    To my surprise, MSVC++ 8.0 prefers to call std::swap for int and int*.
    It only calls ::swap for Foo and Foo*. But GNU g++ 3.4.4 surprises me
    even more, as it never calls any of my ::swap overloads at all, and
    always prefers calling std::swap instead! So what's the Standard
    compliant way?


    Kind regards

    Niels Dekker
    xs4all.nl/~nd/dekkerware
    Niels Dekker (no reply address), Jul 19, 2006
    #1
    1. Advertising

  2. Niels Dekker (no reply address)

    werasm Guest

    Niels Dekker (no reply address) wrote:
    > When calling swap as follows (as recommanded in Effective C++, 3rd
    > Edition, by Scott Meyers), what swap is chosen to be called?
    > using std::swap;
    > swap(a, b);
    >
    > Suppose there is a global ::swap function provided, whose parameter type
    > matches closer to the type of a and b than any of the std::swap
    > overloads does. Will this ::swap be called, or is std::swap still
    > preferred?


    "using std::swap" would mean std::swap would be taken into
    consideration when establishing the initial overload set. Usually, when
    all aspects of overload resolution are equal, non-templates would be
    preferred.

    > #include <algorithm>
    > struct Foo {};
    >
    > void swap(int &, int &) {}
    > void swap(Foo &, Foo &) {}
    > template<typename T> void swap(T*&, T*&) {}
    >
    > int main()
    > {
    > using std::swap;
    >
    > int i1, i2;
    > swap(i1, i2);



    I would call you swap(int&,int&) a perfect match here, and would put my
    money on it being called everytime.


    >
    > int *ptr1, *ptr2;
    > swap(ptr1, ptr2);


    Your (template) version of swap is more specialized than the std::swap
    - therefore it should be called here (I'm using SGI std::swap as
    reference).

    SGI...
    template <class Assignable>
    void swap(Assignable& a, Assignable& b);
    ....
    It may be possible that other libs have more specialized swaps for
    pointers. If this is the case (IMO), you should get ambiguities.

    >
    > Foo foo1, foo2;
    > swap(foo1, foo2);


    void swap(Foo &, Foo &), for the same reason - non-templates preferred.

    >
    > Foo *foo_ptr1, *foo_ptr2;
    > swap(foo_ptr1, foo_ptr2);


    Once again, your template version is more specialized.


    > }
    >
    > To my surprise, MSVC++ 8.0 prefers to call std::swap for int and int*.


    This is surprising IMhO, and would like someone to educate me too in
    the event of me being wrong :). I don't consider the compilers std
    compliant, but I may be wrong.

    Kind regards,

    Werner
    werasm, Jul 19, 2006
    #2
    1. Advertising

  3. In article <>,
    "Niels Dekker (no reply address)" <> wrote:

    > Will this ::swap be called, or is std::swap still
    > preferred? I ask this because the compilers I tried disagree! So will
    > any of the ::swap functions I defined down below be called in the
    > following main()?
    >
    > #include <algorithm>
    > struct Foo {};
    >
    > void swap(int &, int &) {}
    > void swap(Foo &, Foo &) {}
    > template<typename T> void swap(T*&, T*&) {}
    >
    > int main()
    > {
    > using std::swap;
    >
    > int i1, i2;
    > swap(i1, i2);
    >
    > int *ptr1, *ptr2;
    > swap(ptr1, ptr2);
    >
    > Foo foo1, foo2;
    > swap(foo1, foo2);
    >
    > Foo *foo_ptr1, *foo_ptr2;
    > swap(foo_ptr1, foo_ptr2);
    > }
    >
    > To my surprise, MSVC++ 8.0 prefers to call std::swap for int and int*.
    > It only calls ::swap for Foo and Foo*. But GNU g++ 3.4.4 surprises me
    > even more, as it never calls any of my ::swap overloads at all, and
    > always prefers calling std::swap instead! So what's the Standard
    > compliant way?


    swap(i1, i2);

    This calls std::swap. The function-local using declaration hides the
    global swaps from ordinary lookup, but not ADL. The global swap isn't
    found via ADL because there is no namespace associated with int.

    swap(ptr1, ptr2);

    This calls std::swap, for the same reasons as the previous call.

    swap(foo1, foo2);

    This calls ::swap(Foo&,Foo&). Ordinary lookup does not find this, but
    ADL kicks in and searches the namespace associated with Foo (global).

    swap(foo_ptr1, foo_ptr2);

    This calls ::swap(T*&, T*&). Ordinary lookup does not find this, but
    ADL kicks in and searches the namespace associated with Foo (global).

    An interesting experiment is to move the using declaration to namespace
    scope (above main), and reexamine.

    -Howard
    Howard Hinnant, Jul 19, 2006
    #3
  4. Niels Dekker (no reply address)

    werasm Guest

    Howard Hinnant wrote:

    > This calls std::swap. The function-local using declaration hides the
    > global swaps from ordinary lookup, but not ADL. The global swap isn't
    > found via ADL because there is no namespace associated with int.


    Interesting. I was under the impression that because main is defined in
    the global scope, using declarations in it become associated with the
    global scope. This is obviously wrong - it becomes associated with the
    function scope, which takes precedence over the global scope. Therefore
    the initial overload set considered is that within function scope
    (which is what can be found via ADL and what is part of function scope
    by local using). I thought I would learn by taking the shot :)


    > An interesting experiment is to move the using declaration to namespace
    > scope (above main), and reexamine.


    Quick guess is that it will work iaw. with my original thought, as the
    global swaps and std::swap would form part of the same overload set,
    and the OP's swaps are more specialized?

    Kind regards,

    W
    werasm, Jul 19, 2006
    #4
  5. Thanks very much to you both, Werner and Howard!

    > int main()
    > {
    > using std::swap;
    >
    > int i1, i2;
    > swap(i1, i2);


    Howard Hinnant wrote:
    > This calls std::swap. The function-local using declaration hides the
    > global swaps from ordinary lookup, but not ADL. The global swap isn't
    > found via ADL because there is no namespace associated with int.



    It's clear to me now :)


    Kind regards,

    Niels
    Niels Dekker (no reply address), Jul 20, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Jansson
    Replies:
    5
    Views:
    6,294
    Ivan Vecerina
    Mar 17, 2005
  2. Vinu
    Replies:
    4
    Views:
    353
    Jim Langston
    Jul 7, 2005
  3. Vinu
    Replies:
    0
    Views:
    351
  4. Jason Heyes
    Replies:
    8
    Views:
    717
    Andrew Koenig
    Jan 15, 2006
  5. Jeffrey Walton
    Replies:
    10
    Views:
    937
    Mathias Gaunard
    Nov 26, 2006
Loading...

Share This Page