What swap is called when using std::swap?

  • Thread starter Niels Dekker (no reply address)
  • Start date
N

Niels Dekker (no reply address)

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
 
W

werasm

Niels said:
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
 
H

Howard Hinnant

"Niels Dekker (no reply address) said:
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
 
W

werasm

Howard said:
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
 
N

Niels Dekker (no reply address)

Thanks very much to you both, Werner and Howard!
int main()
{
using std::swap;

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

Howard said:
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top