2017-02-06 11 views
3

Рассмотрим этого куска коды:Неоднозначный вызова при рекурсивном вызове функции VARIADIC шаблона перегрузки

template<typename FirstArg> 
void foo() 
{ 
} 

template<typename FirstArg, typename... RestOfArgs> 
void foo() 
{ 
    foo<RestOfArgs...>(); 
} 

int main() 
{ 
    foo<int, int, int>(); 
    return 0; 
} 

Это не компилируется из-за неоднозначный вызов foo<RestOfArgs...>(); когда RestOfArgs имеет только один элемент ({int}).

Но это компилируется без ошибок:

template<typename FirstArg> 
void foo(FirstArg x) 
{ 
} 

template<typename FirstArg, typename... RestOfArgs> 
void foo(FirstArg x, RestOfArgs... y) 
{ 
    foo(y...); 
} 

int main() 
{ 
    foo<int, int, int>(5, 6, 7); 
    return 0; 
} 

Почему неоднозначность в первом случае?

Почему во втором случае нет двусмысленности?

+0

Мое предположение, что это имеет какое-то отношение тот факт, что сигнатура функции является ее аргументом, и что '' и '' неразличимы в одном случае, но в другом случае. – yeputons

+0

Посмотрите на [overload_resolution] (http://en.cppreference.com/w/cpp/language/overload_resolution) и [Function_template_overloading] (http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading) – Jarod42

+0

@ Jarod42 Я посмотрел на него, но до сих пор не знаю ответа на мои вопросы. –

ответ

1

Почему существует двусмысленность в первом случае?

RestOfArgs может быть пустым.

Так foo<int> может быть создан как:

template<int> 
void foo() 
{ 
} 

и

template<int,> 
void foo() 
{ 
    foo<>(); 
} 

как компилируется, так неоднозначно.

Фактически foo<>() не будет компилироваться, но в следующем экземпляре это не сработает, поэтому это не имеет значения.

Почему нет двусмысленности во втором случае?

foo<int>(7) может быть создан как:

template<int> 
void foo(int 7) 
{ 
} 

и

template<int> 
void foo(int 7) 
{ 
    foo(); 
} 

но второй один ошибка, потому что нет Foo не принимает никаких аргументов, поэтому единственным кандидатом является первым один, поэтому не будет двусмысленно

+0

Не могли бы вы объяснить [этот пример] (http://ideone.com/ZQz8Le)? Я удалил вызовы 'foo' и все еще компилируется. – yeputons

+0

@yeputons конечно, без рекурсивного вызова, используется только шаблон VAARG. –

+0

@yeputons, не используйте SO в качестве консультационной услуги. Это хороший ответ на ваш вопрос. Если у вас есть другие вопросы, задайте другой вопрос. –

0

The answer by @ZangMingJie отвечает на различия в поведении, которое вы наблюдаете в своем коде.

Мне было проще понять разрешение имен со следующими изменениями:

template<typename FirstArg> 
void foo() 
{ 
    printf("1\n"); 
} 

template<typename FirstArg, typename SecondArg, typename... RestOfArgs> 
void foo() 
{ 
    printf("2\n"); 
    foo<SecondArg, RestOfArgs...>(); 
} 

int main() 
{ 
    foo<int, int, int>(); 
    return 0; 
} 

При наличии используются два или более параметров шаблона, то вторая функция вызывается,. Когда есть один параметр шаблона, запускается первая функция.

+0

Это работает и решает проблему двусмысленности, но я до сих пор не знаю почему. На мой первоначальный вопрос пока не ответил. –

+0

@rubix_addict, я думал, что ответ Занга объяснил проблему. –

+0

@RSahu: Я так не думаю, как он объясняет, SFINAE по содержанию определения функции будет использоваться, что неверно: -/ – Jarod42

1

В Function template overloading

Существует много правил, чтобы сказать, какой шаблон функции является более специализированной (в соответствии с заданными параметрами).

Точка, которая делает

template<typename> void foo(); 
template<typename, typename...> void foo(); 

неоднозначный для foo<int>(), но не

template<typename T> void foo(T); 
template<typename T, typename... Ts> void foo(T, Ts...); 

для foo(42) является следующее:

In case of a tie, if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack.

+0

Разве это предложение не предполагает, что в обоих случаях не должно быть какой-либо двусмысленности? Ну, «трейлинг-пакет параметров» ... немного неоднозначен (предназначен для каламбуров) - он может применяться как к «пакетному набору параметров шаблона», так и к «набору параметров функций». –

+0

Я согласен с тем, что недостаточно IMO, но «trailing» не будет применяться к шаблону void f (Leading, std :: tuple , Trailing) 'vs 'template void f (A, std :: tuple <>, B)'. который похож на ваши случаи. – Jarod42

+0

, но в обоих случаях пакеты параметров «trailing» –