2010-02-01 18 views
13

¿Alguien puede resumir la idea de la sobrecarga de plantilla de función? ¿Qué importa, parámetro de plantilla o parámetro de función? ¿Qué pasa con el valor de retorno?plantilla de función sobrecarga

Por ejemplo, dada una plantilla de función

template<typename X, typename Y> void func(X x, Y y) {}; 

¿cuál es la plantilla de función sobrecargada?

1) template<typename X> void func(X x, int y) {};  
2) template<typename X, typename Y> X func(X x, Y y) {};  
3) template<class X, class Y, class Z> void func(X x, Y y, Z z) {}; 
+13

Todos los caracteres ';' posteriores son inútiles. No son necesarios y en realidad lo hacen más confuso de mirar. – Omnifarious

Respuesta

21

De esa lista solo la segunda introduce ambigüedad, porque las funciones, independientemente de si son plantillas, no se pueden sobrecargar según el tipo de devolución.

Puede usar los otros dos:

template<typename X> void func(X x, int y); 

se utilizará si el segundo argumento de la llamada es un int, por ejemplo func("string", 10);

template<class X, class Y, class Z> void func(X x, Y y, Z z); 

se utilizará si se llama a func con tres argumentos.


No entiendo por qué algunas otras respuestas se menciona que las funciones de plantilla y la sobrecarga de funciones no se mezcla. Ciertamente lo hacen, y hay reglas especiales sobre cómo se selecciona la función para llamar.

14.5.5

A function template can be overloaded with other function templates and with normal (non-template) functions. A normal function is not related to a function template (i.e., it is never considered to be a specialization), even if it has the same name and type as a potentially generated function template specialization.)

A no moldeados (o "menos templated") de sobrecarga se prefiere a las plantillas, por ejemplo

template <class T> void foo(T); 
void foo(int); 

foo(10); //calls void foo(int) 
foo(10u); //calls void foo(T) with T = unsigned 

Su primera sobrecarga con un parámetro de no molde también cae bajo esta regla.

elección dada entre varias plantillas, se prefieren los partidos más especializados:

template <class T> void foo(T); 
template <class T> void foo(T*); 

int i; 
int* p; 
int arr[10]; 

foo(i); //calls first 
foo(p); //calls second 
foo(arr); //calls second: array decays to pointer 

Puede encontrar una descripción más formal de todas las reglas en el mismo capítulo de la norma (plantillas de función)


Y, finalmente, hay algunas situaciones en las que dos o más sobrecargas serían ambiguas:

template <class T> void foo(T, int); 
template <class T> void foo(int, T); 

foo(1, 2); 

Aquí la llamada es ambigua, porque ambos candidatos son igualmente especializados.

Puede desambiguar tales situaciones con el uso de (por ejemplo) boost::disable_if. Por ejemplo, podemos especificar que cuando T = int, entonces la segunda sobrecarga no debería incluirse como un candidato de sobrecarga:

#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_same.hpp> 
template <class T> 
void foo(T x, int i); 

template <class T> 
typename boost::disable_if<boost::is_same<int, T> >::type 
foo(int i, T x); 

foo(1, 2); //calls the first 

Aquí la biblioteca produce un "fallo de sustitución" en el tipo de retorno de la segunda sobrecarga , si T = int, eliminándolo del conjunto de candidatos de sobrecarga.

En la práctica, rara vez debe encontrarse en situaciones como esa.

+0

¡Gracias por la corrección! – Potatoswatter

+0

Tenga en cuenta que, para 'plantilla void func (T); plantilla void func (T *); 'también es posible crear una versión que maneje específicamente arreglos:' plantilla función vacía ((T &)[N]);) Esto evita que la matriz se descomponga en un puntero y llame la versión del puntero. –

+0

Estoy tratando de usar 'template class_name :: class_name (const T &);' y 'template class_name :: class_name (const T *);' para instanciar un objeto de clase, pero cada vez que paso un char array intenta llamar 'class_name (const T &)' en lugar de 'class_name (const T *)'. Me aparece un mensaje de error include/Class_name.h | 67 | error: no hay función de coincidencia para llamar a 'to_string (const char [43]) '| porque, en 'class_name (const T &)' Estoy usando 'to_string (T)' mientras estoy en 'class_name (const T *)' Estoy especialmente entregando arreglos de caracteres. –

1

Estoy corregido - ver los comentarios a continuación. No cambiaré ninguna de mis publicaciones originales, ya que eso eliminaría el contexto de las respuestas. Doy gracias a los comentaristas por su entrada, y por ser tan amable de no que vote por


Considere plantillas a ser como el pre-procesador de macros, que se expande #defines antes de que el compilador llega a verlos.

El compilador "ampliará" los parámetros de su plantilla y luego verá sus declaraciones de funciones. Entonces, parámetro de plantilla == parámetro de función. Si declara la misma función dos veces, obtendrá un error.

Pregunta sobre el tipo de devolución. Eso es parte de la 'firma' de la función. Dos funciones con los mismos parámetros pero diferentes tipos de devolución son dos funciones diferentes.

+4

El tipo de devolución de una función que no es de plantilla _no_ es parte de su firma (véase http://stackoverflow.com/questions/290038/is-the-return-type-part-of-the-function-signature/290048#290048) –

+1

La comparación con las macros del preprocesador es bastante defectuosa. Hay reglas especiales sobre sobrecargas. Si tiene 'template void foo (T);' y 'void foo (int);', una llamada como 'foo (3);' definitivamente se resolverá a la última (no se prefieren plantillas sobre las plantillas si coinciden) exactamente). – UncleBens

+0

si el tipo de devolución formaba parte de la signiture que podría sobrecargar en el tipo de retruncado, que no puede –

3

Aquí hay dos cosas separadas: plantilla de funciones y sobrecarga de funciones. Es probable que dos declaraciones distintas de plantilla sean sobrecargas, por lo que su pregunta no tiene sentido, como se dijo. (Las tres "sobrecargas" que das no se basan en la primera plantilla, sino que tienes cuatro sobrecargas para el mismo nombre de función.) El problema real es, dadas algunas sobrecargas y una llamada, ¿cómo llamar a la sobrecarga deseada?

En primer lugar, el tipo de devolución no participa en el proceso de sobrecarga ya sea que haya o no una plantilla involucrada. Entonces # 2 nunca jugará bien con # 1.

En segundo lugar, las reglas para la resolución de sobrecarga de la plantilla de función son diferentes de las reglas de especialización de plantilla de clase más utilizadas. Tanto esencialmente resolver el mismo problema, pero

  • las reglas para plantillas de clase son más simples y más potente, lo que permite, por ejemplo, la recursividad y funciones (usuario) que sólo difieren en el tipo de retorno
  • las reglas para las plantillas de función permiten al compilador para averiguar los argumentos de plantilla de los tipos de argumentos función

usted puede ser capaz de resolver su problema particular con sobrecargas plantilla de función, pero es posible que tenga problemas para la fijación de cualquier error que surge como las reglas son más largos y menos personas están familiarizado con sus complejidades. Después de algunos años de hackeo de plantilla, no sabía que la sobrecarga de la plantilla de función sutil era posible. En bibliotecas como Boost y STL de GCC, un enfoque alternativo es omnipresente. Utilice una clase contenedora de plantilla:

template< typename X, typename Y > 
struct functor { 
    void operator()(X x, Y y); 
}; 
template< typename X > // partial specialization: 
struct functor< X, int > { // alternative to overloading for classes 
    void operator()(X x, int y); 
}; 

Ahora sacrificar la sintaxis de instancias implícita (sin paréntesis).Si quieres conseguir que de nuevo, necesita otra función

template< typename X, typename Y > void func(X x, Y y) { 
    return functor< X, Y >()(x, y); 
} 

estaría interesado en saber si la sobrecarga de funciones puede hacer nada (además de la deducción) que clase de especialización [parcial] no se puede ...

Y luego, por supuesto, su sobrecarga n. ° 3 nunca tendrá ambigüedad porque tiene una cantidad diferente de argumentos que cualquier otra sobrecarga.

+0

+1 para obtener información general sobre la especialización parcial –

+0

Su ejemplo no parece ser ambiguo. La llamada coincide con la segunda (un parámetro coincide con int exactamente). Quizás se refería a sobrecargas como: 'plantilla void func (int x, X y); template void func (X x, int y); ' – UncleBens

+0

Segundo' func' rechazará algunos de los argumentos aceptados por el primer 'func' pero no al revés, lo que hace que la plantilla sea más especializada. Para una llamada de función simple, si ignoramos este orden, la llamada sería ambigua, porque el parámetro de la plantilla también se deduce a 'int'. –

Cuestiones relacionadas