Краткая история: перегружайте, когда можете, специализируйте, когда вам нужно.
Длинная история: C ++ относится к специализации и перегружается совсем по-другому. Это лучше всего объяснить на примере.
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload of foo(T)
template <> void foo<int>(int*); // specialisation of foo(T*)
foo(new int); // calls foo<int>(int*);
Теперь давайте поменяемся местами последние два.
template <typename T> void foo(T);
template <> void foo<int*>(int*); // specialisation of foo(T)
template <typename T> void foo(T*); // overload of foo(T)
foo(new int); // calls foo(T*) !!!
Компилятор выполняет разрешение перегрузки, даже не обращая внимания на специализации. Таким образом, в обоих случаях разрешение перегрузки выбирает foo(T*)
. Однако, только в первом случае он находит foo<int*>(int*)
, потому что во втором случае специализация int*
является специализацией foo(T)
, а не foo(T*)
.
Вы упомянули std::swap
. Это еще более усложняет ситуацию.
Стандарт гласит, что вы можете добавить специализации в пространство имен std
. Отлично, у вас есть какой-то тип Foo
и у него есть производительный своп, тогда вы просто специализируете swap(Foo&, Foo&)
в пространстве имен std
. Нет проблем.
Но что, если Foo
класс шаблона? C ++ не имеет частичной специализации функций, поэтому вы не можете специализироваться swap
. Ваш единственный выбор - перегрузка, но стандарт гласит, что вы не можете добавлять перегрузки в пространство имен std
!
На данный момент у вас есть два варианта:
Создайте функцию swap(Foo<T>&, Foo<T>&)
в своем собственном пространстве имен и надеемся, что она будет найдена через ADL. Я говорю «надежда», потому что если стандартная библиотека вызывает swap, как std::swap(a, b);
, то ADL просто не будет работать.
Игнорировать часть стандарта, в которой говорится не добавлять перегрузки и делать это в любом случае. Честно говоря, даже если это технически запрещено, во всех реалистичных сценариях это сработает.
Однако следует помнить, что нет никакой гарантии, что стандартная библиотека вообще использует swap
. Большинство алгоритмов используют std::iter_swap
, а в некоторых реализациях, на которые я смотрел, он не всегда перенаправляет на std::swap
.