std::swap() is used by many std containers (such as std::list and std::vector) during sorting and even assignment.
But the std implementation of swap() is very generalized and rather inefficient for custom types.
Thus efficiency can be gained by overloading std::swap() with a custom type specific implementation. But how can you implement it so it will be used by the std containers?
The right way to overload std::swap's implemention (aka specializing it), is to write it in the same namespace as what you're swapping, so that it can be found via argument-dependent lookup (ADL). One particularly easy thing to do is:
class X
{
// ...
friend void swap(X& a, X& b)
{
using std::swap; // bring in swap for built-in types
swap(a.base1, b.base1);
swap(a.base2, b.base2);
// ...
swap(a.member1, b.member1);
swap(a.member2, b.member2);
// ...
}
};
Attention Mozza314
Here is a simulation of the effects of a generic std::algorithm calling std::swap, and having the user provide their swap in namespace std. As this is an experiment, this simulation uses namespace exp instead of namespace std.
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
exp::swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
namespace exp
{
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
For me this prints out:
generic exp::swap
If your compiler prints out something different then it is not correctly implementing "two-phase lookup" for templates.
If your compiler is conforming (to any of C++98/03/11), then it will give the same output I show. And in that case exactly what you fear will happen, does happen. And putting your swap into namespace std (exp) did not stop it from happening.
Dave and I are both committee members and have been working this area of the standard for a decade (and not always in agreement with each other). But this issue has been settled for a long time, and we both agree on how it has been settled. Disregard Dave's expert opinion/answer in this area at your own peril.
This issue came to light after C++98 was published. Starting about 2001 Dave and I began to work this area. And this is the modern solution:
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
void swap(A&, A&)
{
printf("swap(A, A)\n");
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
Output is:
swap(A, A)
Update
An observation has been made that:
namespace exp
{
template <>
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
works! So why not use that?
Consider the case that your A is a class template:
// simulate user code which includes <algorithm>
template <class T>
struct A
{
};
namespace exp
{
template <class T>
void swap(A<T>&, A<T>&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A<int> a[2];
exp::algorithm(a, a+2);
}
Now it doesn't work again. :-(
So you could put swap in namespace std and have it work. But you'll need to remember to put swap in A's namespace for the case when you have a template: A<T>. And since both cases will work if you put swap in A's namespace, it is just easier to remember (and to teach others) to just do it that one way.
You're not allowed (by the C++ standard) to overload std::swap, however you are specifically allowed to add template specializations for your own types to the std namespace. E.g.
namespace std
{
template<>
void swap(my_type& lhs, my_type& rhs)
{
// ... blah
}
}
then the usages in the std containers (and anywhere else) will pick your specialization instead of the general one.
Also note that providing a base class implementation of swap isn't good enough for your derived types. E.g. if you have
class Base
{
// ... stuff ...
}
class Derived : public Base
{
// ... stuff ...
}
namespace std
{
template<>
void swap(Base& lha, Base& rhs)
{
// ...
}
}
this will work for Base classes, but if you try to swap two Derived objects it will use the generic version from std because the templated swap is an exact match (and it avoids the problem of only swapping the 'base' parts of your derived objects).
NOTE: I've updated this to remove the wrong bits from my last answer. D'oh! (thanks puetzk and j_random_hacker for pointing it out)
While it's correct that one shouldn't generally add stuff to the std:: namespace, adding template specializations for user-defined types is specifically allowed. Overloading the functions is not. This is a subtle difference :-)
17.4.3.1/1
It is undefined for a C++ program to add declarations or definitions
to namespace std or namespaces with namespace std unless otherwise
specified. A program may add template specializations for any
standard library template to namespace std. Such a specialization
(complete or partial) of a standard library results in undefined
behaviour unless the declaration depends on a user-defined name of
external linkage and unless the template specialization meets the
standard library requirements for the original template.
A specialization of std::swap would look like:
namespace std
{
template<>
void swap(myspace::mytype& a, myspace::mytype& b) { ... }
}
Without the template<> bit it would be an overload, which is undefined, rather than a specialization, which is permitted. #Wilka's suggest approach of changing the default namespace may work with user code (due to Koenig lookup preferring the namespace-less version) but it's not guaranteed to, and in fact isn't really supposed to (the STL implementation ought to use the fully-qualified std::swap).
There is a thread on comp.lang.c++.moderated with a long dicussion of the topic. Most of it is about partial specialization, though (which there's currently no good way to do).
Related
I have a library which expose some sort of container struct in which I want to collect diverse generic type of data which might be from the same namespace of the library as well as data from the std namespace such as array or tuple or pairs.
This container has a print_all method which will invoke operator<< for all the elements in the container. Such an operator is supposed to be provided by the user of the library.
Testing the library, I am using different template parameters for T, but I do not care too much about what is being printed by the print_all method. For the test purpose I care only that an example character is being printed no matter which T is being tested. Actually, I my real code I am using Google Test Framework and the behavior of the method under test is really asserted to be the same for every data type provided.
I tried to provide both a generic version of operator<< and two specific versions of it. You can see them in between the #if directive. None of the two compilation branches compiles correctly, most likely because of some violation of the König lookup rules. But anyway what I want to do should be easily possible somehow. What am I missing?
Here is the example code:
#include <algorithm>
#include <iostream>
#include <vector>
namespace my
{
template<typename DataType>
struct Container
{
void print_all( std::ostream& os ) const
{
std::for_each(std::begin(data),
std::end(data),
[&os](const DataType& value)
{
os << value;
});
}
std::vector<DataType> data;
};
namespace test
{
struct Data
{
std::byte data[4];
};
using Array = std::array<std::byte,4>;
#if 0
template<typename T>
std::ostream& operator<<(std::ostream& os, const T& data)
{
return os << 'X';
}
#else
std::ostream& operator<<(std::ostream& os, const Data& data)
{
return os << 'X';
}
std::ostream& operator<<(std::ostream& os, const Array& data)
{
return os << 'X';
}
#endif
void run()
{
// Test with custom data
{
Container< Data> container;
container.data.resize(1);
container.print_all( std::cout );
}
// Test with std data
{
Container< Array> container;
container.data.resize(1);
container.print_all( std::cout );
}
}
} // namespace test
} // namespace my
int main()
{
my::test::run();
return 0;
}
ADL looks into the namespaces associates with the arguments.
using Array = std::array<std::byte,4>;
this type test::Array is an alias. The namespaces associated with it for the purpose of ADL is std. test is not associated with it. ADL will only look in std. You are not permitted to add operators to std; if you violate that, your program is ill-formed, no diagnostic required. ADL cannot help you, because it only helps people who own the namespace(s) associated with the arguments.
Any << you want to support in std needs to be in namespace my, defined before your print_all function.
Your code for Data looks to me like it works, I assume your question was just poorly written, as it implies os <<Data does not work. If I am wromg amd it doesn't work, it is because of some typo; ADL works fine on structs, but not on aliases. In the future, please include complete error messages when code doesn't work.
I want perfect forwarding but I already know (and only accept) the type my function will take.
Here is a quick example I typed up:
class big_class
{
private:
std::string m_somethingBig;
};
class testmove
{
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
m_bigClasses.push_back(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
m_bigClasses.push_back(big);
}
private:
std::vector<big_class> m_bigClasses;
};
int main()
{
testmove tm;
big_class big;
tm.Add(big);
tm.Add(big_class{});
}
Live Sample
Is it possible to do some form of implementation sharing between the two overloads of testmove::Add()? I want to optimize for move, and if someone does std::move() without my rvalue overload it will end up doing at least 1 copy before it is added to my vector.
Again, I realize I can solve this problem by making Add() a template function, and even using type traits and some template trickery. But I wanted to avoid this if possible. If you need to know why, I have a few reasons:
I can't do implementation hiding with a template (restrict includes and symbol visibility to a single translation unit)
Using a template here gives me more flexibility than I want (My contract requires I only use a big_class).
Using a template would impact readability/maintainability for what should be a simple interface.
The approach suggested by Xeo (take the parameter by value) is the one I would strongly recommend. However, if for some reason you can't do that (e.g., moves are expensive but less so than copies), keep reading.
I think it's possible to satisfy all your criteria, but it's only worth it if the code is complicated enough so that duplicating it would be bad. The idea is to delegate to a template that will be explicitly instantiated only for big_class.
big_class.h:
// ...
public:
void Add(big_class&& big)
{
Add_internal(std::move(big));
}
void Add(big_class const& big)
{
Add_internal(big);
}
private:
// not part of interface; defined in .cpp file
template <typename T> void Add_internal(T&& big);
big_class.cpp:
// implementation of template
template <typename T> void big_class::Add_internal(T&& big) {
// shared logic goes here
m_bigClasses.push_back(std::forward<T>(big));
}
// explicit instantiation
template void big_class::Add_internal<big_class>(big_class&&);
template void big_class::Add_internal<big_class const&>(big_class const&);
if you really can't stand the idea of adding by value, you may provide one internal templated impl:
private:
template<class X>
auto add_impl(X&& x) {
m_bigClasses.push_back(std::forward<X>(x));
}
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
add_impl(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
add_impl(std::move(big));
}
How can this work? you're moving a const ref!
Because std::move does not move anything. It merely casts an l-value reference to an r-value reference. So const T& becomes a const T&&, which no-one ever codes for. So it will decay to match the const T& or T that people do code for.
Are we supposed to be able to inherit from Qt containers such as QList, QVector or QMap in order to specialize them and add functionality? If so, what do we need to do in order to be sure that the container works correctly (virtual methods, virtual destructor etc..?). If not, why not and what other options do I have?
Both, STL and Qt Containers opt for non virtual destructors.
There is an interesting discussion why this is, and why its not fixed with Qt5.
QList has no virtual destructor, but is inherited from http://qt-project.org/forums/viewthread/16416
Also, note further differences between STL style and Qt containers. Quoting Jens Weller in his Blog post An introduction into Qt:
Still, there is an important difference between Qt containers and STL containers: Qt containers have value semantics, and will only perform copy on write, while a std container will copy its full contents when copied. This behavoir accounts for most of Qt base classes, that they will only create a new instance for data, when needed. This implicit sharing of resources is a very important concept to understand when dealing with Qt and its containers.
Your options are as always:
composition
E.g.
struct MyFancyList
{
QList<MyType> _data;
bool frobnicate() { return true; }
};
free functions
E.g. extend QList with non-member operations:
template <typename> bool frobnicate(QList<T>& list)
{
// your algorithm
return true;
}
If you really wanted to do funcky stuff, like create an implicit conversion or overload a member operator, you could resort to expression templates.
Update: the latter is also the approach taken by QStringBuilder in new versions. See
Lecture: Expression Templates (video, slides) by Volker Krause
Bonus
For fun, here's a (bad!) illustration of how you could use expression templates to extend the interface of std::stack<T>. See it Live on Coliru or ideone
As we all know, std::stack doesn't model a sequential container, and therefore doesn't have begin(), end(), or operator[] defined. With a bit of hackery, we can define a eDSL to provide these features, without composition or inheritance.
To really drive the point home that you can 'overload' behaviour of the wrapped class in essential ways, we'll make it so that you can implicitly convert the result of extend(stack)[n] to a std::string, even if the stack contains e.g. int.
#include <string>
#include <stack>
#include <stdexcept>
namespace exprtemplates
{
template <typename T> struct stack_indexer_expr
{
typedef std::stack<T> S;
S& s;
std::size_t n;
stack_indexer_expr(S& s, std::size_t n) : s(s), n(n) {}
operator T() const {
auto i = s.size()-n; // reverse index
for (auto clone = s; !clone.empty(); clone.pop())
if (0 == --i) return clone.top();
throw std::range_error("index out of bounds in stack_indexer_expr");
}
operator std::string() const {
// TODO use `boost::lexical_cast` to allow wider range of T
return std::to_string(this->operator T());
}
};
template <typename T> struct stack_expr
{
typedef std::stack<T> S;
S& s;
stack_expr(S& s) : s(s) {}
stack_indexer_expr<T> operator[](std::size_t n) const {
return { s, n };
}
};
}
Now all we have to do is seed our expression templates. We'll use a helper function that wraps any std::stack:
template <typename T>
exprtemplates::stack_expr<T> extend(std::stack<T>& s) { return { s }; }
Ideally, our users never realize the exact types inside exprtemplates namespace:
#include <iostream>
int main()
{
std::stack<double> s;
s.push(0.5);
s.push(0.6);
s.push(0.7);
s.push(0.8);
std::string demo = extend(s)[3];
std::cout << demo << "\n";
}
Voila. More craziness:
auto magic = extend(s);
std::cout << magic[0] << "\n";
std::cout << magic[1] << "\n";
std::cout << magic[2] << "\n";
std::cout << magic[3] << "\n";
double as_double = magic[0];
std::string as_string = magic[0];
Prints
0.5
0.6
0.7
0.8
DISCLAIMERS
I know std::stack has a restrictive interface for a reason.
I know that my indexing implementation has horrific efficiency.
I know that implicit conversions are evil. This is just a contrived example.
In real life, use Boost::Proto to get a DSL going. There are many pitfalls and gotchas in doing all the mechanics by hand.
Look at QStringBuilder for a more real life sample.
What is the preferred method of using std::rel_ops to add the full set of relational operators to a class?
This documentation suggests a using namespace std::rel_ops, but this seems to be deeply flawed, as it would mean that including the header for the class implemented in this way would also add full relational operators to all other classes with a defined operator< and operator==, even if that was not desired. This has the potential to change the meaning of code in surprising ways.
As a side note - I have been using Boost.Operators to do this, but I am still curious about the standard library.
The way operator overloads for user defined classes was meant to work is via argument dependent lookup. ADL allows programs and libraries to avoid cluttering up the global namespace with operator overloads, but still allow convenient use of the operators; That is, without explicit namespace qualification, which is not possible to do with the infix operator syntax a + b and would instead require normal function syntax your_namespace::operator+ (a, b).
ADL, however, doesn't just search everywhere for any possible operator overload. ADL is restricted to look only at 'associated' classes and namespaces. The problem with std::rel_ops is that, as specified, this namespace can never be an associated namespace of any class defined outside the standard library, and therefore ADL cannot work with such user defined types.
However, if you're willing to cheat you can make std::rel_ops work.
Associated namespaces are defined in C++11 3.4.2 [basic.lookup.argdep] /2. For our purposes the important fact is that the namespace of which a base class is a member is an associated namespace of the inheriting class, and thus ADL will check those namespaces for appropriate functions.
So, if the following:
#include <utility> // rel_ops
namespace std { namespace rel_ops { struct make_rel_ops_work {}; } }
were to (somehow) find its way into a translation unit, then on supported implementations (see next section) you could then define your own class types like so:
namespace N {
// inherit from make_rel_ops_work so that std::rel_ops is an associated namespace for ADL
struct S : private std::rel_ops::make_rel_ops_work {};
bool operator== (S const &lhs, S const &rhs) { return true; }
bool operator< (S const &lhs, S const &rhs) { return false; }
}
And then ADL would work for your class type and would find the operators in std::rel_ops.
#include "S.h"
#include <functional> // greater
int main()
{
N::S a, b;
a >= b; // okay
std::greater<N::s>()(a, b); // okay
}
Of course adding make_rel_ops_work yourself technically causes the program to have undefined behavior because C++ does not allow user programs to add declarations to std. As an example of how that actually does matter and why, if you do this, you may want to go to the trouble of verifying that your implementation does in fact work properly with this addition, consider:
Above I show a declaration of make_rel_ops_work that follows #include <utility>. One might naively expect that including this here doesn't matter and that as long as the header is included sometime prior to the use of the operator overloads, then ADL will work. The spec of course makes no such guarantee and there are actual implementations where that is not the case.
clang with libc++, due to libc++'s use of inline namespaces, will (IIUC) consider that declaration of make_rel_ops_work to be in a distinct namespace from the namespace containing the <utility> operator overloads unless <utility>'s declaration of std::rel_ops comes first. This is because, technically, std::__1::rel_ops and std::rel_ops are distinct namespaces even if std::__1 is an inline namespace. But if clang sees that the original namespace declaration for rel_ops is in an inline namespace __1, then it will treat a namespace std { namespace rel_ops { declaration as extending std::__1::rel_ops rather than as a new namespace.
I believe this namespace extension behavior is a clang extension rather than specified by C++, so you may not even be able to rely on this in other implementations. In particular gcc does not behave this way, but fortunately libstdc++ doesn't use inline namespaces. If you don't want to rely on this extension then for clang/libc++ you can write:
#include <__config>
_LIBCPP_BEGIN_NAMESPACE_STD
namespace rel_ops { struct make_rel_ops_work {}; }
_LIBCPP_END_NAMESPACE_STD
but obviously then you'll need implementations for other libraries you use. My simpler declaration of make_rel_ops_work works for clang3.2/libc++, gcc4.7.3/libstdc++, and VS2012.
I think that the preferred technique is not to use std::rel_ops at
all. The technique used in boost::operator (link) seems to be the usual
solution.
Example:
#include "boost/operators.hpp"
class SomeClass : private boost::equivalent<SomeClass>, boost::totally_ordered<SomeClass>
{
public:
bool operator<(const SomeClass &rhs) const
{
return someNumber < rhs.someNumber;
}
private:
int someNumber;
};
int main()
{
SomeClass a, b;
a < b;
a > b;
a <= b;
a >= b;
a == b;
a != b;
}
The problem with adding the rel_ops namespace, regardless of whether you do it with a manual using namespace rel_ops; or whether you do it automatically as described in the answer by #bames53 is that adding the namespace can have unanticipated side effects on portions of your code. I found this myself just recently as I had been using the #bames53 solution for some time, but when I changed one of my container based operations to use a reverse_iterator instead of an iterator (within a multimap but I suspect it would be the same for any of the standard containers), suddenly I was getting compile errors when using != to compare two iterators. Ultimately I tracked it down to the fact that the code included the rel_ops namespace which was interfering with how reverse_iterators are defined.
Using boost would be a way to solve it, but as mentioned by #Tom not everyone is willing to use boost, myself included. So I implemented my own class to solve the problem, which I suspect is also how boost does it, but I didn't check the boost libraries to see.
Specifically, I have the following structure defined:
template <class T>
struct add_rel_ops {
inline bool operator!=(const T& t) const noexcept {
const T* self = static_cast<const T*>(this);
return !(*self == t);
}
inline bool operator<=(const T& t) const noexcept {
const T* self = static_cast<const T*>(this);
return (*self < t || *self == t);
}
inline bool operator>(const T& t) const noexcept {
const T* self = static_cast<const T*>(this);
return (!(*self == t) && !(*self < t));
}
inline bool operator>=(const T& t) const noexcept {
const T* self = static_cast<const T*>(this);
return !(*self < t);
}
};
To use this, when you define your class, say MyClass, you can inherit from this one to add the "missing" operators. Of course you need to define the == and < operators within MyClass (not shown below).
class MyClass : public add_rel_ops<MyClass> {
...stuff...
};
It is important that you include MyClass as the template argument. If you were to include a different class, say MyOtherClass, the static_cast would be almost certain to give you problems.
Note that my solution is assuming that the == and < operators are defined as const noexcept which is one of the requirements of my personal coding standards. If your standards are different, you would need to modify add_rel_ops accordingly.
In addition, if you are bothered by the use of static_cast, you can change them to be a dynamic_cast by adding
virtual ~add_rel_ops() noexcept = default;
to the add_rel_ops class in order to make it a virtual class. Of course, that will also force MyClass to be a virtual class which is why I do not take that approach.
It's not the nicest, but you can use using namespace std::rel_ops as an implementation detail for implementing the comparison operators on your type. For example:
template <typename T>
struct MyType
{
T value;
friend bool operator<(MyType const& lhs, MyType const& rhs)
{
// The type must define `operator<`; std::rel_ops doesn't do that
return lhs.value < rhs.value;
}
friend bool operator<=(MyType const& lhs, MyType const& rhs)
{
using namespace std::rel_ops;
return lhs.value <= rhs.value;
}
// ... all the other comparison operators
};
By using using namespace std::rel_ops;, we allow ADL to lookup operator<= if it is defined for the type, but fall back onto the one defined in std::rel_ops otherwise.
This is still a pain, though, as you still have to write a function for each of the comparison operators.
std::swap() is used by many std containers (such as std::list and std::vector) during sorting and even assignment.
But the std implementation of swap() is very generalized and rather inefficient for custom types.
Thus efficiency can be gained by overloading std::swap() with a custom type specific implementation. But how can you implement it so it will be used by the std containers?
The right way to overload std::swap's implemention (aka specializing it), is to write it in the same namespace as what you're swapping, so that it can be found via argument-dependent lookup (ADL). One particularly easy thing to do is:
class X
{
// ...
friend void swap(X& a, X& b)
{
using std::swap; // bring in swap for built-in types
swap(a.base1, b.base1);
swap(a.base2, b.base2);
// ...
swap(a.member1, b.member1);
swap(a.member2, b.member2);
// ...
}
};
Attention Mozza314
Here is a simulation of the effects of a generic std::algorithm calling std::swap, and having the user provide their swap in namespace std. As this is an experiment, this simulation uses namespace exp instead of namespace std.
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
exp::swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
namespace exp
{
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
For me this prints out:
generic exp::swap
If your compiler prints out something different then it is not correctly implementing "two-phase lookup" for templates.
If your compiler is conforming (to any of C++98/03/11), then it will give the same output I show. And in that case exactly what you fear will happen, does happen. And putting your swap into namespace std (exp) did not stop it from happening.
Dave and I are both committee members and have been working this area of the standard for a decade (and not always in agreement with each other). But this issue has been settled for a long time, and we both agree on how it has been settled. Disregard Dave's expert opinion/answer in this area at your own peril.
This issue came to light after C++98 was published. Starting about 2001 Dave and I began to work this area. And this is the modern solution:
// simulate <algorithm>
#include <cstdio>
namespace exp
{
template <class T>
void
swap(T& x, T& y)
{
printf("generic exp::swap\n");
T tmp = x;
x = y;
y = tmp;
}
template <class T>
void algorithm(T* begin, T* end)
{
if (end-begin >= 2)
swap(begin[0], begin[1]);
}
}
// simulate user code which includes <algorithm>
struct A
{
};
void swap(A&, A&)
{
printf("swap(A, A)\n");
}
// exercise simulation
int main()
{
A a[2];
exp::algorithm(a, a+2);
}
Output is:
swap(A, A)
Update
An observation has been made that:
namespace exp
{
template <>
void swap(A&, A&)
{
printf("exp::swap(A, A)\n");
}
}
works! So why not use that?
Consider the case that your A is a class template:
// simulate user code which includes <algorithm>
template <class T>
struct A
{
};
namespace exp
{
template <class T>
void swap(A<T>&, A<T>&)
{
printf("exp::swap(A, A)\n");
}
}
// exercise simulation
int main()
{
A<int> a[2];
exp::algorithm(a, a+2);
}
Now it doesn't work again. :-(
So you could put swap in namespace std and have it work. But you'll need to remember to put swap in A's namespace for the case when you have a template: A<T>. And since both cases will work if you put swap in A's namespace, it is just easier to remember (and to teach others) to just do it that one way.
You're not allowed (by the C++ standard) to overload std::swap, however you are specifically allowed to add template specializations for your own types to the std namespace. E.g.
namespace std
{
template<>
void swap(my_type& lhs, my_type& rhs)
{
// ... blah
}
}
then the usages in the std containers (and anywhere else) will pick your specialization instead of the general one.
Also note that providing a base class implementation of swap isn't good enough for your derived types. E.g. if you have
class Base
{
// ... stuff ...
}
class Derived : public Base
{
// ... stuff ...
}
namespace std
{
template<>
void swap(Base& lha, Base& rhs)
{
// ...
}
}
this will work for Base classes, but if you try to swap two Derived objects it will use the generic version from std because the templated swap is an exact match (and it avoids the problem of only swapping the 'base' parts of your derived objects).
NOTE: I've updated this to remove the wrong bits from my last answer. D'oh! (thanks puetzk and j_random_hacker for pointing it out)
While it's correct that one shouldn't generally add stuff to the std:: namespace, adding template specializations for user-defined types is specifically allowed. Overloading the functions is not. This is a subtle difference :-)
17.4.3.1/1
It is undefined for a C++ program to add declarations or definitions
to namespace std or namespaces with namespace std unless otherwise
specified. A program may add template specializations for any
standard library template to namespace std. Such a specialization
(complete or partial) of a standard library results in undefined
behaviour unless the declaration depends on a user-defined name of
external linkage and unless the template specialization meets the
standard library requirements for the original template.
A specialization of std::swap would look like:
namespace std
{
template<>
void swap(myspace::mytype& a, myspace::mytype& b) { ... }
}
Without the template<> bit it would be an overload, which is undefined, rather than a specialization, which is permitted. #Wilka's suggest approach of changing the default namespace may work with user code (due to Koenig lookup preferring the namespace-less version) but it's not guaranteed to, and in fact isn't really supposed to (the STL implementation ought to use the fully-qualified std::swap).
There is a thread on comp.lang.c++.moderated with a long dicussion of the topic. Most of it is about partial specialization, though (which there's currently no good way to do).