809. std::swap should be overloaded for array types

Section: 26.7.3 [alg.swap] Status: CD1 Submitter: Niels Dekker Opened: 2008-02-28 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [alg.swap].

View all issues with CD1 status.

Discussion:

For the sake of generic programming, the header <algorithm> should provide an overload of std::swap for array types:

template<class T, size_t N> void swap(T (&a)[N], T (&b)[N]);

It became apparent to me that this overload is missing, when I considered how to write a swap function for a generic wrapper class template. (Actually I was thinking of Boost's value_initialized.) Please look at the following template, W, and suppose that is intended to be a very generic wrapper:

template<class T> class W {
public:
  T data;
};

Clearly W<T> is CopyConstructible and CopyAssignable, and therefore Swappable, whenever T is CopyConstructible and CopyAssignable. Moreover, W<T> is also Swappable when T is an array type whose element type is CopyConstructible and CopyAssignable. Still it is recommended to add a custom swap function template to such a class template, for the sake of efficiency and exception safety. (E.g., Scott Meyers, Effective C++, Third Edition, item 25: Consider support for a non-throwing swap.) This function template is typically written as follows:

template<class T> void swap(W<T>& x, W<T>& y) {
  using std::swap;
  swap(x.data, y.data);
}

Unfortunately, this will introduce an undesirable inconsistency, when T is an array. For instance, W<std::string[8]> is Swappable, but the current Standard does not allow calling the custom swap function that was especially written for W!

W<std::string[8]> w1, w2;  // Two objects of a Swappable type.
std::swap(w1, w2);  // Well-defined, but inefficient.
using std::swap;
swap(w1, w2);  // Ill-formed, just because ADL finds W's swap function!!!

W's swap function would try to call std::swap for an array, std::string[8], which is not supported by the Standard Library. This issue is easily solved by providing an overload of std::swap for array types. This swap function should be implemented in terms of swapping the elements of the arrays, so that it would be non-throwing for arrays whose element types have a non-throwing swap.

Note that such an overload of std::swap should also support multi-dimensional arrays. Fortunately that isn't really an issue, because it would do so automatically, by means of recursion.

For your information, there was a discussion on this issue at comp.lang.c++.moderated: [Standard Library] Shouldn't std::swap be overloaded for C-style arrays?

Proposed resolution:

Add an extra condition to the definition of Swappable requirements [swappable] in 16.4.4.2 [utility.arg.requirements]:

- T is Swappable if T is an array type whose element type is Swappable.

Add the following to 26.7.3 [alg.swap]:

template<class T, size_t N> void swap(T (&a)[N], T (&b)[N]);

Requires: Type T shall be Swappable.

Effects: swap_ranges(a, a + N, b);