40

Un libro de texto Tengo notas de que puede proporcionar su propia implementación para funciones de biblioteca estándar como swap(x,y) a 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é).Especialización de plantilla VS Función de sobrecarga

Mis preguntas son:

  1. ¿Qué es mejor: la especialización de plantilla para darle a su aplicación especializada de intercambio o sobrecarga de funciones que proporciona los parámetros exactos que desea utilizar sin una plantilla?

  2. ¿Por qué es mejor? O si son iguales, ¿por qué es esto?

Respuesta

60

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:

  1. 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á.

  2. 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.

+0

gran ejemplo señor – tenfour

+6

"Digo esperanza porque" ... Se observó este punto en WG21 hace varios años. Todos los implementadores de bibliotecas estándar saben que no. – MSalters

+0

Maravillosa respuesta, muchas gracias. –

5

No tiene permiso para sobrecargar las funciones en el espacio de nombres std, pero puede autorizar las plantillas (como recuerdo), de modo que esa es una opción.

La otra opción es poner su función swap en el mismo espacio de nombres en el que está operando y using std::swap; antes de llamar a un intercambio no calificado.

+0

Prefiero 'usar std :: swap;' a 'usando namespace std;'. –

+0

Puede especializar algunas plantillas: _ "Un programa puede agregar una especialización de plantilla para cualquier plantilla de biblioteca estándar al espacio de nombres std solo si la declaración depende de un tipo definido por el usuario y la especialización cumple con los requisitos de biblioteca estándar para la plantilla original y no explícitamente prohibido. "_ [n3337; 17.6.4.2.1/1] Así que puede especializar 'std :: swap' para tipos que no están en' std'. – boycy

+0

¿por qué no puede sobrecargar las funciones estándar? es un mal hábito, pero el espacio de nombres estándar no es especial. No me gusta, pero muchos productos agregan el intercambio estándar para sus tipos en el espacio de nombres estándar. – Nick

10

Hay poco que añadir 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 las funciones sin los parámetros.

E.g.

template<class T> T zero(); 
template<> int zero() { return 0; } 
template<> long zero() { return 0L; } 

hacer algo similar con la sobrecarga de funciones, habría que añadir un parámetro a la función de firma:

int zero(int) { return 0; } 
long zero(long) { return 0L; } 
+1

Uso interesante :) –

Cuestiones relacionadas