c++ - Especialización de plantillas VS Sobrecarga de funciones
stl template-specialization (3)
Cuento corto: sobrecarga cuando puedas, especialízate cuando lo necesites.
Larga historia: 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 sobrecarga la resolución 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 foo(T*)
.
Usted mencionó std::swap
. Esto hace las cosas aún más complicadas.
El estándar dice que puede agregar especializaciones al std
nombres estándar. Genial, entonces tienes algún tipo de Foo
y tiene un intercambio de rendimiento, entonces solo especializas swap(Foo&, Foo&)
en el std
nombres std
. No hay problemas.
Pero, ¿y si Foo
es una clase de plantilla? C ++ no tiene una especialización parcial de funciones, por lo que no puede especializar el swap
. Su única opción es sobrecargar, pero el estándar dice que no tiene permitido agregar sobrecargas en el std
nombres estándar.
Tienes dos opciones en este punto:
Cree una función de
swap(Foo<T>&, Foo<T>&)
en su propio espacio de nombres y espere que se encuentre a través de ADL. Digo "esperanza" porque si la biblioteca estándar llama a swap comostd::swap(a, b);
entonces ADL simplemente no funcionará.Ignora la parte del estándar que dice no agregar sobrecargas y hazlo 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 use swap
. La mayoría de los algoritmos usan std::iter_swap
y en algunas implementaciones que he visto, no siempre se reenvía a std::swap
.
Un libro de texto Tengo notas de que puede proporcionar su propia implementación para funciones de biblioteca estándar como swap(x,y)
través de la especialización de plantillas para la sobrecarga de funciones. Esto sería útil para cualquier tipo que se pueda beneficiar de algo más que un intercambio de tareas, como STL containers
por ejemplo (que ya tienen swaps escritos, lo sé).
Mis preguntas son:
¿Qué es mejor: especialización de plantilla para dar su implementación especializada de intercambio, o sobrecarga de función que proporciona los parámetros exactos que desea utilizar sin una plantilla?
¿Por qué es mejor? O si son iguales, ¿por qué es esto?
Hay poco que agregar a la respuesta de Peter Alexander. Permítanme mencionar un uso en el que la especialización de funciones podría ser preferible a la sobrecarga: si tiene que seleccionar entre funciones sin parámetros .
P.ej
template<class T> T zero();
template<> int zero() { return 0; }
template<> long zero() { return 0L; }
Para hacer algo similar con la sobrecarga de funciones, debería agregar un parámetro a la firma de la función:
int zero(int) { return 0; }
long zero(long) { return 0L; }
No está permitido sobrecargar funciones en el std
nombres std
, pero se le permite especializar plantillas (como recuerdo), así que esa es una opción.
La otra opción es poner su función de swap
en el mismo espacio de nombres en el que está operando y using std::swap;
antes de llamar a un intercambio no calificado.