Я могу думать только о нескольких различиях - вот несколько примеров, которые не обязательно причиняют вред (я думаю). Я опускаю определения для краткости
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
template <> int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses explicit specialization
// --- against ---
template <typename T> T inc(const T& t);
namespace G { using ::inc; }
int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses template
Это связано с тем, что специализации обнаруживаются не при поиске по имени, а по сопоставлению аргументов, поэтому объявление об использовании автоматически учитывает введенную позже специализацию.
Тогда вы, конечно, не можете частично специализировать шаблоны функций. Перегрузка, однако, приводит к чему-то очень похожему путем частичного упорядочения (используя разные типы, чтобы выразить свою точку зрения)
template <typename T> void f(T t); // called for non-pointers
template <typename T> void f(T *t); // called for pointers.
int a;
void e() {
f(a); // calls the non-pointer version
f(&a); // calls the pointer version
}
Это было бы невозможно при явной специализации шаблона функции. Другой пример - когда задействованы ссылки, что приводит к выводу аргумента шаблона для поиска точного соответствия задействованных типов (по модулю базовых / производных отношений классов и константности):
template<typename T> void f(T const &);
template<> void f(int * const &);
template<typename T> void g(T const &);
void g(int * const &);
int a[5];
void e() {
// calls the primary template, not the explicit specialization
// because `T` is `int[5]`, not `int *`
f(a);
// calls the function, not the template, because the function is an
// exact match too (pointer conversion isn't costly enough), and it's
// preferred.
g(a);
}
Я рекомендую вам всегда использовать перегрузку, потому что она богаче (допускает что-то вроде частичной специализации), и, кроме того, вы можете поместить функцию в любое пространство имен, которое вы хотите (хотя тогда это больше не будет строго перегружено). Например, вместо того, чтобы специализировать std::swap
в пространстве имен std::
, вы можете поместить перегрузку swap
в свое собственное пространство имен и сделать ее вызываемой по ADL.
Что бы вы ни делали, никогда не смешивает специализацию и перегрузку , это будет адский беспорядок, подобный , на который указывает эта статья . Стандарт имеет прекрасный параграф об этом
Размещение явных объявлений специализации для шаблонов функций, шаблонов классов, функций-членов шаблонов классов, статических данных-членов шаблонов классов, классов-членов шаблонов классов, шаблонов классов-членов шаблонов классов, шаблонов функций-членов шаблонов классов, члена функции шаблонов-членов шаблонов классов, функции-члены шаблонов-членов не шаблонных классов, шаблоны функций-членов классов-членов шаблонов классов и т. д., а также размещение объявлений частичной специализации шаблонов классов, шаблонов классов-членов не-шаблона классы, шаблоны классов членов шаблонов классов и т. д. могут влиять на то, правильно ли сформирована программа в соответствии с относительным расположением явных объявлений специализации и их точек создания в единице перевода, как указано выше и ниже. При написании специализации будьте осторожны с ее местоположением; или сделать его компиляцией будет таким испытанием, чтобы разжечь его самосожжение.