Cuento corto: sobrecarga cuando puedas, especialízate cuando lo necesites.
Relato largo: C++ trata la especialización y las sobrecargas de manera muy diferente. Esto se explica mejor con un ejemplo.
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*);
Ahora intercambiemos los dos últimos.
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*) !!!
El compilador tiene una resolución de sobrecarga incluso antes de ver las especializaciones. Entonces, en ambos casos, la resolución de sobrecarga elige foo(T*)
. Sin embargo, solo en el primer caso encuentra foo<int*>(int*)
porque en el segundo caso la especialización int*
es una especialización de foo(T)
, no de foo(T*)
.
Usted mencionó std::swap
. Esto hace las cosas aún más complicadas.
La norma dice que puede agregar especializaciones al espacio de nombre std
. Genial, entonces tiene algún tipo de Foo
y tiene un intercambio de rendimiento, entonces solo se especializa en swap(Foo&, Foo&)
en el espacio de nombres std
. No hay problemas.
¿Pero y si Foo
es una clase de plantilla? C++ no tiene especialización parcial de funciones, por lo que no puede especializar swap
. Su única opción es sobrecargar, pero el estándar dice que no tiene permitido agregar sobrecargas en el espacio de nombres std
.
usted tiene dos opciones en este punto:
crear una función swap(Foo<T>&, Foo<T>&)
en su propio espacio de nombres, y esperamos que se encuentra a través de la ADL. Digo "esperanza" porque si la biblioteca estándar llama a swap como std::swap(a, b);
entonces ADL simplemente no funcionará.
Ignore la parte del estándar que dice no agregar sobrecargas y hágalo de todos modos. Honestamente, a pesar de que técnicamente no está permitido, en todos los escenarios realistas va a funcionar.
Una cosa para recordar es que no hay garantía de que la biblioteca estándar utiliza swap
en absoluto. La mayoría de los algoritmos usan std::iter_swap
y en algunas implementaciones que he visto, no siempre se envían a std::swap
.
gran ejemplo señor – tenfour
"Digo esperanza porque" ... Se observó este punto en WG21 hace varios años. Todos los implementadores de bibliotecas estándar saben que no. – MSalters
Maravillosa respuesta, muchas gracias. –