I came upon an interesting conundrum yesterday. I realised that when writing generic (i.e. templated) code for things such as sorting algorithms (a hobby of mine) that it would be useful to know whether or not a given data type has a specialised std::swap.

Take for example an insertion sort algorithm. When moving items over to insert an item into place there are two ways of doing it:

1. We can copy the item that we want to insert into a temporary variable, then move items over using one assignment operator call for each one, and then copy the desired item into its place. Or...

2. We can use std::swap to shuffle all those items along until we find the spot where the item should be inserted.

Now for a type which does not have std::swap specialised, (e.g. double) option 1 is the best because most items can be moved with just one assignment operator call. If we used std::swap then moving each item would involve three assignments.

However, for a type which does have std::swap specialised, such as a vector or other such class that has a throwing asignment operator but non-throwing std::swap, option 2 is better and more efficient. With option 2 we can in fact go as far as performing the whole thing without ever invoking the assignment operator. But with option 1 we invoke the potentially expensive and throwing assignment operator many times.

Now the question is. Is there a way of detecting if std::swap is specialised for a given type? Perhaps using SFINAE?

Any other thoughts?

In case it helps, some code for thought:

template <typename T> void InsertionSort1(T a[], int n) { for (int i = 1; i < n; ++i) { if (a[i] < a[i - 1]) { int j = i - 1; const T tempItem = a[i]; do { a[j + 1] = a[j]; --j; } while (j >= 0 && tempItem < a[j]); a[j + 1] = tempItem; } } } template <typename T> void InsertionSort2(T a[], int n) { for (int i = 1; i < n; ++i) { if (a[i] < a[i - 1]) { int j = i - 1; T tempItem; std::swap(tempItem, a[i]); do { std::swap(a[j + 1], a[j]); --j; } while (j >= 0 && tempItem < a[j]); std::swap(a[j + 1], tempItem); } } }