21

I read something interesting today that said the 'standard' way to call swap on a user provided type (provided as a template argument) is...

using std::swap;
swap(something, soemthingelse);

The reason for this is to use argument dependent look-up to either use a swap function in a user namespace or swap in the std namespace. This raised an interested question for me. When I overload std::swap for one of my classes I had actually been defining it in the std namespace... namespace std { void swap(/*...*/){/*...*/} }. Is this practice wrong? Should I define my own swaps in std or my own namespace (and why)?

David
  • 27,652
  • 18
  • 89
  • 138
  • I suppose you could always make an explicit specialization, which *is* allowed... – Kerrek SB Jan 18 '13 at 16:16
  • @KerrekSB Still the question stands if specialization should be discouraged in favour of ADL-enabled own-namespace functions. – Christian Rau Jan 18 '13 at 16:22
  • Don't you get ambiguities if you do both? – Marc Glisse Jan 18 '13 at 16:29
  • @MarcGlisse It will be fine until someone writes `using std::swap;`, and even then if the one in `std` is a specialization and the one in your user defined namespace is just standalone (not even templated actually), it will be fine. – David Jan 18 '13 at 16:30
  • @ChristianRau Actually that sounds like the most solid thing to do. I may start doing that. – David Jan 18 '13 at 16:33
  • @jthill Meh, that actual question is rather about if his approach is standard compliant. Whereas this is also a problem here, the more fundemental problem of this question is much more interresting and not that explicitly asked in that *duplicate*. – Christian Rau Jan 18 '13 at 16:57
  • @FredOverflow Same as with other *duplicate*. While the answers are sufficient for duplicate status, the actual question is not. – Christian Rau Jan 18 '13 at 17:02
  • @ChristianRau ? I'm not getting it. It could certainly be caffeine deprivation, but it seems to me that _question's_ first two sentences answer OP's question completely, it specifically says don't overload, the standard prohibits it, do specialize, it works great. The first answer to that question corrects an easy misunderstanding of what's what. – jthill Jan 18 '13 at 17:27
  • @ChristianRau Ok, I plead caffeine deprivation. I see it now, the "duplicate" I linked is actually giving out subtly wrong information. I deleted my original comment. – jthill Jan 18 '13 at 17:52
  • @jthill You are right, that the difference between overloading and specialization is an important part of this question. But for me the much more interresting part (and the one that was IMHO initially intended by the OP) is the more *"philosophical"* question about whether to specialize `std::swap` or provide your own `swap` function to be resolved by ADL (with the corresponding reasons and implications), which is in the end more or less independent from the question if you specialize or overload `std::swap`... – Christian Rau Jan 18 '13 at 19:24
  • @jthill ...Although that is in part answered by the other question's answers, the actual question doesn't really reflect that. – Christian Rau Jan 18 '13 at 19:28

5 Answers5

21

You're doing it wrong :)

17.6.2.4.1 [namespace.std]

  1. The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

That pretty clearly says you may not add overloads to namespace std. You could specialize std::swap<MyType> for your type, but if your type is a template you'd need a partial specialization, std::swap<MyContainer<T>> and you can't partially specialize a function template, so that won't work, so it's not a good approach in general.

C++11 also defines the requirements for a type to be swappable which include:

17.6.3.2 [swappable.requirements]

  1. ...
  2. ...
  3. The context in which swap(t, u) and swap(u, t) are evaluated shall ensure that a binary non-member function named "swap" is selected via overload resolution (13.3) on a candidate set that includes:
  • the two swap function templates defined in <utility> (20.2) and
  • the lookup set produced by argument-dependent lookup (3.4.2).

So calling swap on two objects of swappable type should be able to find std::swap and should be able to find other overloads by ADL. Calling it unqualified (and without an explicit template argument list) ensures ADL happens, and including <utility> and adding the using-declaration for std::swap ensures the standard overloads can be found. So doing it the way you show in your question meets those requirements.

That pretty clearly defines what it takes to be swappable in the sense used by the standard, which is what is required by the standard library e.g. by the functions in <algorithm>.

If you put swap overloads for your type in your type's namespace then they can be found by ADL. That is the right thing to do anyway, functions related to your type belong in the same namespace as your type, see Item 57 in C++ Coding Standards by Sutter and Alexandrescu for more details on that topic.

So in short, you have been doing it wrong. What you read is correct. Doing using std::swap and relying on ADL always works (for templates and non-templates) and avoids undefined behaviour. Yay.

N.B. The C++03 standard was less clear about how user-defined types should be swapped. For some history around this area see N1691 2.2 which defines the term customization point and shows different ways to define them in APIs. The protocol used in C++11 for swapping types uses one of those ways, and is now clearly and unambiguously blessed as the "correct way" to provide a swap function for your type. Other customization points in other libraries can use other approaches, but to be swappable in C++11 terms means using std::swap; and relying on ADL.

David G
  • 94,763
  • 41
  • 167
  • 253
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
6

It is legal to provide specializations of standard templates for your own types, and those must go inside the std namespace. So both approaches are legal C++.

That being said, the recommended way is to provide the swap free function in the same namespace as your own type and have ADL pickup your overload from there.


EDIT: After some of the comments I reread the question and noticed that it mentions overloads in the std namespace. It is illegal to provide overloads in the std namespace, only specializations are allowed.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • He said he's adding overloads to `namespace std`, not specializations. So it's illegal. – Jonathan Wakely Jan 18 '13 at 16:50
  • @JonathanWakely In my case I kind of have to overload because the arguments of my swap are templated types. There appears to be no syntax to specialize (I want syntax like this maybe... `template<> template void swap, thing>(thing& left, thing& right);`) – David Jan 18 '13 at 17:04
  • 1
    @Dave Oh, in that case you don't have a chance to provide a proper `std::swap` specialization and won't get around using the ADL-based approach (though in practice a `std::swap`-overload won't hurt anybody, even if being technically disallowed/UB, but it makes an already less-idiomatic solution even more problematic). – Christian Rau Jan 18 '13 at 17:08
  • @Dave, yep, you can't partially specialize a function template, but it's not legal to overload (see my answer). – Jonathan Wakely Jan 18 '13 at 17:10
4

I believe this is the answer you're looking for, and the entire set of answers to that question explain all. Howard Hinnant and Dave Abrahams have been on the C++ standards committee for more than a decade I think.

Community
  • 1
  • 1
jthill
  • 55,082
  • 5
  • 77
  • 137
3

First of all, you are not allowed to add things to std (be it just an overload), so overloading the std::swap is bad practice in the first place. What you can do is specialize existing templates. So you should rather specialize than overload:

namespace std
{
    template<> void swap<MyType>(...) {...}
}

But still the question stands if an own-namespace version is to be preferred over a std-specialization. The idomatic recommended way is to provide a free swap in your own namespace and let ADL resolve it, like David already suggests. The problem with this is, that if someone (the client of your library) is not that well-versed in idiomatic C++ and just explicitly calls std::swap(...) all over the place, you might end up with sub-optimal swapping behaviour. This is the case why I for myself usually went the safe way of doing both (own-namespace function + std-specialization), even if that always has a bad taste to me.

But fortunately C++11 simplifies things, since efficiently moveable types (which are usually also the effieciently swappable ones) can be swapped quite efficiently with the default std::swap, which uses move-semantics. So the possible usage of the default std::swap over your own swap function becomes less of a disadvantage (and you might even consider not bothering to provide one anyway).

So if you have C++11, the best way is indeed to not bother extending std but just define your own swap in your types' namespace, while in C++03 you might want to be on the safe side with a std::swap specialization, even if being less idiomatic.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
0

Ideal thing to do is to provide a public swap member function only when you think that the std::swap would be inefficient for your type. In case you provide a swap member function, it is recommended that you also provide a non-member swap that calls this member function. This makes it easier for other people to call your more efficient template-specific version.

sam
  • 11
  • 1