Clang "не мог вывести шаблонный аргумент", тогда как gcc/g++ может. Какой правильный?
Я пытаюсь скомпилировать проект (который отлично использует gcc/g++) с clang и компиляцией, застрявшей в вызове шаблона.
Я попытался создать простейший аналогичный фрагмент кода с тем же сообщением об ошибке. Вот он:
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
int A( double in )
{
return 1;
}
int A( int in )
{
return 1;
}
template<class M, class T>
M test(T input, M (fun) (T) )
{
return fun( input );
}
int main( int argc, const char *argv[] )
{
cout << test( (int) 1, A ) << test( (double) 1.2, A ) << endl;
return 0;
}
Ошибка от clang (отображается дважды, конечно):
error: no matching function for call to 'test'
candidate template ignored: couldn't infer template argument 'M'
Gcc не жалуется.
Обратите внимание: M - это тип возврата и всегда "int".
Кто-нибудь знает, что правильно и почему?
Спасибо
Ответы
Ответ 1
Мой предыдущий ответ (теперь удален) был неправильным. Кланг ошибочен.
Компилятор должен иметь возможность выводить тип M
, потому что аргумент функции M(fun)(T)
. Обратите внимание, что в списке аргументов указателя функции нет M
, поэтому это соответствует T()
(С++ 11)/T(*)()
(С++ 93) в 14.8.2.5:
где (T)
представляет список параметров-типа, где хотя бы один тип параметра содержит T
, а ()
представляет список параметров-параметров, где тип параметра не содержит T
.
Ответ 2
g++ неверен. Из С++ 11 [temp.deduct.type] p5:
Невыводимые контексты: [...] - Параметр функции, для которого вывод аргумента не может быть выполнен, потому что связанный аргумент функции [...] представляет собой набор перегруженных функций, а [...] более одной функции соответствует тип параметра функции
Это определение выполняется без учета параметров шаблона, которые могли быть выведены в другом месте, поэтому факт, что T
должен выводиться как int
, здесь не имеет значения. Это делает весь параметр M (fun)(T)
не выводимым контекстом. Поэтому M
не может быть выведено, как утверждает Кланг.
g++, по-видимому, неправильно использует вывод 'T
= int
' из первого параметра функции при определении того, является ли второй параметр невыводимым контекстом. Обратный порядок параметров функции заставляет g++ также отклонять код:
int A(double);
int A(int);
template<class M, class T>
M test(M (fun) (T), T input) {
return fun( input );
}
int main( int argc, const char *argv[]) {
test(A, 1);
test(A, 1.2);
}