Ответ 1
Рассказ: перегрузите, когда сможете, специализируйтесь, когда вам нужно.
Длинная история: С++ рассматривает специализацию и перегрузки по-разному. Это лучше всего объяснить с помощью примера.
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
- это шаблонный класс? С++ не имеет частичной специализации функций, поэтому вы не можете специализировать swap
. Ваш единственный выбор - перегрузка, но стандарт говорит, что вам не разрешено добавлять перегрузки в пространство имен std
!
На данный момент у вас есть два варианта:
-
Создайте функцию
swap(Foo<T>&, Foo<T>&)
в своем собственном пространстве имен и надейтесь, что она будет найдена через ADL. Я говорю "надеюсь", потому что, если стандартная библиотека вызывает swap какstd::swap(a, b);
, то ADL просто не будет работать. -
Игнорируйте часть стандарта, которая говорит, что не добавлять перегрузки и делать это в любом случае. Честно говоря, хотя это технически не разрешено, во всех реалистичных сценариях он будет работать.
Одна вещь, которую следует помнить, заключается в том, что нет гарантии, что стандартная библиотека вообще использует swap
. Большинство алгоритмов используют std::iter_swap
и в некоторых реализациях, на которые я смотрел, он не всегда пересылает std::swap
.