Of that list only the second introduces ambiguity, because functions - regardless of whether they are templates - can't be overloaded based on return type.
You can use the other two:
template<typename X> void func(X x, int y);
will be used if the second argument of the call is an int, e.g func("string", 10);
template<class X, class Y, class Z> void func(X x, Y y, Z z);
will be used if you call func with three arguments.
I don't understand why some other answers mentions that template functions and function overloading doesn't mix. They certainly do, and there are special rules how the function to call is selected.
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 non-templated (or "less templated") overload is preferred to templates, e.g
template <class T> void foo(T);
void foo(int);
foo(10); //calls void foo(int)
foo(10u); //calls void foo(T) with T = unsigned
Your first overload with one non-template parameter also falls under this rule.
Given choice between several templates, more specialized matches are preferred:
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
You can find a more formal description of all the rules in the same chapter of the standard (Function templates)
And finally there are some situations where two or more overloads would be ambiguous:
template <class T> void foo(T, int);
template <class T> void foo(int, T);
foo(1, 2);
Here the call is ambiguous, because both candidates are equally specialized.
You can disambiguate such situations with the use of (for example) boost::disable_if
. For example, we can specify that when T = int, then the second overload shouldn't be included as an overload candidate:
#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
Here the library produces a "substitution failure" in the return type of the second overload, if T = int, removing it from the set of overload candidates.
In practice you should rarely run into situations like that.