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.
Todos los caracteres ';' posteriores son inútiles. No son necesarios y en realidad lo hacen más confuso de mirar. – Omnifarious