Учитывая этот код, как вывод аргумента шаблона определяет, что делать для последнего вызова функции?
#include <iostream>
template<typename Ret, typename... Args>
Ret foo(Args&&...) {
std::cout << "not void\n";
return {};
}
template<typename... Args>
void foo(Args&&...) {
std::cout << "void\n";
}
int main() {
foo(3, 'a', 5.4); //(1): prints "void"
foo<int, char>(3, 'a', 5.4); //(2): prints "void"
foo<int>('a', 5.4); //(3): prints "not void"
foo<int>(3, 'a', 5.4); //(4): prints "not void"
}
(1) кажется довольно простым. Он не может выводить возвращаемый тип, поэтому используется версия void
.
(2) явно указывает некоторые типы аргументов. Первый аргумент шаблона соответствует первому аргументу, второй аргумент шаблона соответствует второму аргументу, и выводится третий аргумент шаблона. Если для возвращаемого типа использовался int
, char
не соответствовал первому аргументу.
(3) делает то же самое, что и (2), но первые типы не совпадают. Следовательно, это должно быть выведено как возвращаемый тип и два аргумента, используемые для вывода двух аргументов Args
.
(4) кажется неоднозначным. Он явно указывает аргумент шаблона, как и (2) и (3). Аргумент шаблона соответствует аргументу, как и (2). Однако он не использует это как первое и выводит два других, а скорее использует явный аргумент шаблона как возвращаемый тип и выводит все три аргумента Args
.
Почему (4) кажется наполовину следовать (2), но затем использовать другую версию? Самое лучшее, что у меня есть, это то, что единственный параметр шаблона, который заполняется, лучше сочетается, чем только пакет параметров. Где стандарт определяет это поведение?
Это было скомпилировано с использованием GCC 4.8.0. Для удобства здесь выполните тестовый прогон на Coliru.
В Clang 3.1, однако, (4) не компилируется из-за двусмысленности (см. комментарии). Это открывает возможность того, что один из этих двух компиляторов имеет ошибку. Сделать эту возможность более вероятно, так это то, что компилятор Visual Studio 2012 November CTP дает тот же результат, что и Clang, при этом (4) является двусмысленным.