Из этого списка только вторая вносит неоднозначность, поскольку функции - независимо от того, являются ли они шаблонами - не могут быть перегружены на основе типа возвращаемого значения.
Вы можете использовать два других:
template<typename X> void func(X x, int y);
будет использоваться, если вторым аргументом вызова является int, например, func("string", 10);
template<class X, class Y, class Z> void func(X x, Y y, Z z);
будет использоваться, если вы вызовете func с тремя аргументами.
Я не понимаю, почему в некоторых других ответах упоминается, что функции шаблона и перегрузка функций не смешиваются. Они, конечно, делают, и есть специальные правила, как выбирается функция для вызова.
14.5.5
Шаблон функции может быть
перегружен другой функцией
шаблоны и с нормальным
(не шаблонные) функции. Нормальный
функция не связана с
шаблон функции (т.е. это никогда не
считается специализацией),
даже если оно имеет то же имя и тип
как потенциально сгенерированная функция
специализация шаблона.)
Не шаблонная (или "менее шаблонная") перегрузка предпочтительнее шаблонов, например
template <class T> void foo(T);
void foo(int);
foo(10); //calls void foo(int)
foo(10u); //calls void foo(T) with T = unsigned
Ваша первая перегрузка с одним не шаблонным параметром также подпадает под это правило.
При выборе между несколькими шаблонами предпочтительны более специализированные совпадения:
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
Более формальное описание всех правил вы можете найти в той же главе стандарта ( Шаблоны функций )
И, наконец, есть ситуации, когда две или более перегрузок будут неоднозначными:
template <class T> void foo(T, int);
template <class T> void foo(int, T);
foo(1, 2);
Здесь призыв неоднозначен, поскольку оба кандидата одинаково специализированы.
Вы можете устранить неоднозначность в таких ситуациях с помощью (например) boost::disable_if
. Например, мы можем указать, что когда T = int, вторая перегрузка не должна включаться в качестве кандидата на перегрузку:
#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
Здесь библиотека выдает «сбой замещения» в типе возврата второй перегрузки, если T = int, удаляя его из набора кандидатов на перегрузку.
На практике вам редко приходится сталкиваться с подобными ситуациями.