2013-07-23 11 views
19

Próbowałem skompilować projekt (który jest w porządku przy użyciu gcc/g ++) z klang i kompilacji zatrzymanych na szablonie wywołania. Próbowałem utworzyć najprostszy podobny fragment kodu z tym samym komunikatem o błędzie. Oto ona:Clang "nie może wywnioskować argumentu szablonu", podczas gdy gcc/g ++ może. Który jest poprawny?

#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; 
} 

Błąd z brzękiem (pojawia się dwa razy oczywiście):

error: no matching function for call to 'test' 
candidate template ignored: couldn't infer template argument 'M' 

GCC nie narzekać. Uwaga: M jest typem zwrotnym i zawsze jest "int".

Czy ktoś wie, co jest poprawne i dlaczego?

Dzięki

+0

czy zamiast tego spróbowałeś użyć testu (..., & A)? –

+0

Stefano: Próbowałem, to nie miało znaczenia. – Max

+0

I nie powinno. Nie ma potrzeby używania operatora adresu dla nazwy funkcji, aby uzyskać wskaźnik funkcji. (I podobnie, nie ma potrzeby jawnego dereferencji wskaźnika funkcji za pomocą '*', aby go wywołać.) Chociaż możesz, jeśli naprawdę chcesz, ale to nie ma znaczenia. – BoBTFish

Odpowiedz

2

Moja poprzednia odpowiedź (teraz usunięta) była nieprawidłowa. Clang jest złe.

Kompilator powinien być w stanie wywnioskować typ M, ponieważ argumentem funkcji jest M(fun)(T). Zauważ, że nie ma M w liście argumentów wskaźnik funkcji, więc odpowiada to T() (C++ 11)/T(*)() (C++ 93) w 14.8.2.5:

gdzie (T) reprezentuje parametr -type-list, gdzie co najmniej jeden typ parametru zawiera T, i () reprezentuje listę parametrów typu, gdzie żaden typ parametru nie zawiera T.

+1

+1, ponieważ uważam, że masz rację i jest to błąd klang. –

+0

Czy nie powinien on być "typ (T)" zgodny z normą? – maverik

+0

@maverik - Nie. Do analizy typu szablonu 'T' można użyć' T() 'lub' T (T) '. Zauważ, że '()' nie oznacza funkcji, która nie przyjmuje żadnych argumentów. Oznacza to po prostu, że żaden z argumentów funkcji nie zawiera "T". –

8

g ++ jest nieprawidłowy. Od C++ 11 [temp.deduct.type] P5:

Objęte zakazem wywnioskować konteksty są: [...] - parametr funkcji, dla których odliczenie argumentu nie można zrobić, ponieważ wiąże się funkcja argument jest [...] zestaw przeciążonych funkcji, a [...] więcej niż jedna funkcja odpowiada typowi parametru funkcja

To określenie jest wykonany bez względu na parametry szablonów, które mogły zostać wyprowadzona gdzie indziej, więc Fakt, że T musi wydedukować jako int, nie jest tutaj odpowiedni. Powoduje to, że cały parametr nie ma wydedukowanego kontekstu. Zatem nie można wywnioskować, że M, tak jak twierdzi Clang.

g ++ wydaje się nieprawidłowo używać "dedukcji" z pierwszego parametru funkcji przy określaniu, czy drugi parametr nie jest kontekstem wywnioskowanym. Odwrócenie kolejności parametrów funkcji powoduje, że g ++ również odrzuca kod:

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); 
} 
+0

To wygląda poprawnie. (Jedna rzecz, która wprawiła mnie w zakłopotanie przez chwilę: "parametr funkcji", który jest kontekstem nie wydedukowanym, to 'M (zabawa) (T)', a nie parametr do 'A'. Chociaż odpowiedź to wyjaśniła.) – aschepler

+0

Tego typu rzeczy wolę używać funktorów wszędzie tam, gdzie to możliwe, zamiast wskaźników funkcyjnych. – SirGuy

Powiązane problemy