Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does C++11 change the behavior of explicitly calling std::swap to ensure ADL-located swap's are found, like boost::swap?

69 views
Skip to first unread message

GMan

unread,
Feb 16, 2012, 1:42:27 AM2/16/12
to
[I've asked this question on StackOverflow (http://stackoverflow.com/
questions/9170247/does-c11-change-the-behavior-of-explicitly-calling-
stdswap-to-ensure-adl-loc), but the question has stagnated, and I
think it's because SO doesn't contain the right audience to fully
answer the question. (Of those who could, they just haven't seen it.)]

For the nicely formatted version of the question with examples, see
the above link, but to summarize: does std::swap take on the behavior
of boost::swap in C++11? If not, why?

In other words, is the following supposed to work in C++11?

#include <utility>

namespace ns
{
struct foo
{
foo() : i(0) {}
int i;

private:
foo(const foo&); // not defined,
foo& operator=(const foo&); // non-copyable
};

void swap(foo& lhs, foo& rhs)
{
std::swap(lhs.i, rhs.i);
}
}

int main()
{
ns::foo a, b;
std::swap(a, b); // finds ns::swap internally, or tries to copy
(and fails)?
}

I posted an SO answer showing that it's easily possible in principle,
yet both MSVC and GCC don't seem to take that route. (They do follow
the new mandate that all calls to swap *elsewhere* in the stdlib be
done without qualification, though. To me this is proof enough that
the committee could have discussed it.)

So what I'm looking for is a definite, "yes, GCC and MSVC are wrong
and here's why", "no, it was brought up and rejected and here's why",
or, "no, but only because it definitely wasn't brought up." The only
answer on SO suggests the last of those options, but it's not very
confident about it. Thanks.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler

unread,
Feb 16, 2012, 4:27:45 PM2/16/12
to
On 2012-02-16 07:42, GMan wrote:
> For the nicely formatted version of the question with examples, see
> the above link, but to summarize: does std::swap take on the behavior
> of boost::swap in C++11? If not, why?

It does not and the short answer is: If it would do so, it could
silently change the meaning of valid C++03 code. See below for more details.

> In other words, is the following supposed to work in C++11?
>
> #include<utility>
>
> namespace ns
> {
> struct foo
> {
> foo() : i(0) {}
> int i;
>
> private:
> foo(const foo&); // not defined,
> foo& operator=(const foo&); // non-copyable
> };
>
> void swap(foo& lhs, foo& rhs)
> {
> std::swap(lhs.i, rhs.i);
> }
> }
>
> int main()
> {
> ns::foo a, b;
> std::swap(a, b); // finds ns::swap internally, or tries to copy
> (and fails)?
> }

The explicit call of std-qualified swap will only consider the generic
std::swap function (and std::pair's swap overload) which imposes the
MoveConstructible and MoveAssignable requirements. If you want to enable
ADL, you need to replace

std::swap(a, b);

by

using std::swap;
swap(a, b);

This is the way how the swappable requirements are defined in C++11.

> I posted an SO answer showing that it's easily possible in principle,
> yet both MSVC and GCC don't seem to take that route.

The compiler behaviour is conforming.

> (They do follow
> the new mandate that all calls to swap *elsewhere* in the stdlib be
> done without qualification, though. To me this is proof enough that
> the committee could have discussed it.)

The definition of the swappable requirements had been discussed
thoroughly, yes.

> So what I'm looking for is a definite, "yes, GCC and MSVC are wrong
> and here's why", "no, it was brought up and rejected and here's why",
> or, "no, but only because it definitely wasn't brought up." The only
> answer on SO suggests the last of those options, but it's not very
> confident about it. Thanks.

I'm not 100% sure whether this was explicitly discussed, but it was
clear that changing the semantics of valid C++03 code would not be
acceptable.

There was no much time any more to be very inventive, because concepts
had been deferred late in the game (Those would have a similar effect as
the C++11 Swappable requirements now have, only the "using std::swap"
statement could be excluded, because the resolution would find the
concept swap, which again would find ns::foo's free swap). There was a
late idea to provide adl_swap (or consider any other name *except* swap)
which basically encapsulates the lines

using std::swap;
swap(a, b);

but this would just provide a new function, *not* replace the old one.
It was too late for new components, therefore no concrete proposal
provided (It was discussed, though). But there is no fundamental reason,
why such a function should not be added in the future.

HTH & Greetings from Bremen,

Daniel Krügler

Gil N.

unread,
Feb 18, 2012, 2:20:38 AM2/18/12
to
afaik there were at least these solutions considered to allow users
to supply a optimized implementation for UDT:

a) allow partial specializations for function templates;

b) allow unholy overloads within std:: namespace;

c) list a bunch of std algos that must use unqualified calls
for some set of functions;

d) the mythical additional level of indirection: let users specialize
some helper class templates;

e) focus on swap only and make std::swap to call swap() methods for
UDTs;

in the end they picked (c) (resources, path of least surprise) but
also
introduced [swappable.requirements] and a clarification in bullet
17.6.3.2/3 plus an example specifying that the evaluation context
ensures how swap(t,u) is selected.

hth,
gil
0 new messages