Подтвердить что ты не робот

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".

Кто-нибудь знает, что правильно и почему?

Спасибо

4b9b3361

Ответ 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); 
}