Solo puedo pensar en algunas diferencias: he aquí algunos ejemplos que no necesariamente causan daño (creo). Estoy omitiendo las definiciones para mantenerlo terso
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
Eso se debe a que las especializaciones no se encuentran en la búsqueda de nombres, sino por argumento de comparación, por lo que una declaración using a considerar de forma automática una especialización introducido más tarde.
Entonces, por supuesto, no puede especializar parcialmente las plantillas de funciones.La sobrecarga sin embargo logra algo muy similar por orden parcial (utilizando diferentes tipos ahora, para hacer mi punto)
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
}
que no sería posible con una plantilla de función especialización explícita. Otro ejemplo es cuando se trata de referencias, lo que provoca la deducción argumento de plantilla para buscar una coincidencia exacta de los tipos involucrados (base de módulo/relaciones entre las clases derivadas y constness):
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);
}
recomiendo que utilice siempre sobrecarga, porque es más rica (permite algo así como la especialización parcial), y además puede colocar la función en el espacio de nombres que desee (aunque ya no esté estrictamente sobrecargado). Por ejemplo, en lugar de tener que especializarse en std::swap
en el espacio de nombres std::
, puede colocar su sobrecarga swap
en su propio espacio de nombres y hacer que sea invocable por ADL.
Hagas lo que hagas, nunca mezcle la especialización y la sobrecarga, será un desastre como this article señala. El estándar tiene un párrafo preciosa al respecto
la colocación de las declaraciones especialización explícita de plantillas de funciones, plantillas de clase, funciones miembro de plantillas de clase, los miembros de datos estáticos de plantillas de clase, clases de miembros de plantillas de clase, plantillas de clase miembro de plantillas de clase, plantillas de función miembro de plantillas de clase, funciones miembro de plantillas miembro de plantillas de clase, funciones miembro de plantillas miembro de clases no plantilla, plantillas de función miembro de clases miembro de plantillas de clase, etc., y la colocación de declaraciones de especialización parcial de plantillas de clase, plantillas de clase de miembro de clases que no son de plantilla, plantillas de clase de miembro de plantillas de clase, etc., pueden afectar si un programa está bien formado de acuerdo con el posicionamiento relativo de la especialización explícita decl araciones y sus puntos de instanciación en la unidad de traducción como se especifica arriba y abajo. Al escribir una especialización, tenga cuidado con su ubicación; o para hacer que compile será una prueba que encienda su autoinmolación.
Volví a subir la pregunta porque esta es una de las áreas oscuras en C++ (al menos para mí)! – AraK
¿Qué es lo que pides en particular? Solo algunas diferencias, o algunos casos donde el peligro está en su lugar? Por ejemplo, seguramente 'inc <> (10);' se comporta diferente para estos dos fragmentos, pero ¿es eso lo que quieres escuchar? –