2015-10-01 16 views
9

Rozważmy następujący kod:Odrzucanie argumentów szablonu: który kompilator jest właśnie tutaj?

template<int N> 
class Vector 
{ 
}; 

#include <array> 

template<int N> 
void doWork(const Vector<N>&, const std::array<int,N>&) 
{ 
} 

int main() 
{ 
    std::array<int,3> arr; 
    Vector<3> vec; 
    doWork(vec,arr); 
} 

Tutaj Vector reprezentuje klasę, która jest zdefiniowana w bibliotece stron trzecich, a std::array jest znany do podjęcia jego elementem liczyć jako std::size_t.

Próbowałem skompilować to z clang-3.6 i g ++ - 5.1. Dzyń pracował bez zarzutu, natomiast g ++ daje następujący błąd:

test.cpp: In function ‘int main()’: 
test.cpp:17:19: error: no matching function for call to ‘doWork(Vector<3>&, std::array<int, 3ul>&)’ 
    doWork(vec,arr); 
       ^
test.cpp:9:6: note: candidate: template<int N> void doWork(const Vector<N>&, const std::array<int, N>&) 
void doWork(const Vector<N>&, const std::array<int,N>&) 
    ^
test.cpp:9:6: note: template argument deduction/substitution failed: 
test.cpp:17:19: note: mismatched types ‘int’ and ‘long unsigned int’ 
    doWork(vec,arr); 
       ^
test.cpp:17:19: note: ‘std::array<int, 3ul>’ is not derived from ‘const std::array<int, N>’ 

mogę obejść ten wykonując obsady N do std::size_t w drugim parametrze doWork() lub dzwoniąc doWork<3>(), ale to nie będzie mnie kształcić.

Więc raczej zapytam najpierw: który kompilator jest właśnie tutaj? Czy naprawdę robię coś złego w kodzie (więc klang jest zbyt permisywny), czy rzeczywiście jest to poprawne C++ (tak, że g ++ ma błąd)?

Odpowiedz

4

wierzę gcc jest tutaj poprawne, jeśli pójdziemy do projektu C++ 11 część standardowa 14.8.2.5[temp.deduct.type] mówi:

If, in the declaration of a function template with a non-type template-parameter, the non-type templateparameter is used in an expression in the function parameter-list and, if the corresponding template-argument is deduced, the template-argument type shall match the type of the template-parameter exactly, except that a template-argument deduced from an array bound may be of any integral type.144 [ Example:

template<int i> class A { /* ... */ }; 
template<short s> void f(A<s>); 
void k1() { 
A<1> a; 
f(a); // error: deduction fails for conversion from int to short 
f<1>(a); // OK 
} 

[...]

i możemy zobaczyć, czy możemy zmienić Twój kod do tego:

doWork<3>(vec,arr); 

gcc nie wystawia błędu i nie zadzwoni.

Jeśli spróbujemy ten przykład:

template<int N> 
void doWorkB(std::array<int,N>&) 
{ 
} 

//... 

doWorkB(arr); 

dzyń teraz produkuje błąd (see it live):

note: candidate template ignored: substitution failure : deduced non-type template argument does not have the same type as the its corresponding template parameter ('unsigned long' vs 'int') 
void doWorkB(std::array<int,N>&) 
    ^

Pierwotny przypadek łamie również w brzękiem jeśli zamienić kolejność parametrów:

void doWork(const std::array<int,N>&, const Vector<N>&)