2016-08-08 24 views
9

Natknąłem się na pewne interesujące zachowanie funkcji szablonów wariatów. Czy każdy może wskazać odpowiednie zasady w standardzie, które to definiują?Zaskakujące niezerowe zachowanie pakietów parametrów

GCC, ICC i MSVC skompiluj następujący kod pomyślnie (Clang nie, ale rozumiem, że jest to spowodowane błędami kompilatora).

template<class A, class... Bs, class C> 
void foo(A, Bs..., C) { } 

int main() 
{ 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
} 

W tym wywołaniu foo argumenty szablonu są przewidziane A i Bs, następnie C wyprowadza się int.

Jednakże, jeśli po prostu odwrócić dwa ostatnie parametry szablonu:

template<class A, class C, class... Bs> 
void foo(A, Bs..., C) { } 

następnie allthreecompilers błędy rzut. Oto jeden z GCC:

main.cpp: In function 'int main()': 
main.cpp:8:42: error: no matching function for call to 'foo(int, int, int, int, int)' 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
             ^
main.cpp:4:6: note: candidate: template<class A, class C, class ... Bs> void foo(A, Bs ..., C) 
void foo(A, Bs..., C) { } 
     ^~~ 
main.cpp:4:6: note: template argument deduction/substitution failed: 
main.cpp:8:42: note: candidate expects 4 arguments, 5 provided 
    foo<int, int, int, int>(1, 2, 3, 4, 5); 
            ^

Żeby było ciekawiej, nazywając tylko czterech argumentów invalid dla pierwszego foo i valid na sekundę.

Wydaje się, że w pierwszej wersji foo, Cmusi wywnioskować, natomiast w drugim, Cmusi być jawnie dostarczone.

Jakie zasady w standardzie definiują to zachowanie?

+3

Powiedziałbym, że pierwszy przykład, ten, który kompiluje, nie powinien. Jest źle sformułowany. –

+0

@SamVarshavchik Czy możesz wyjaśnić, dlaczego? – TartanLlama

+0

Szablon jest jawnie tworzony z czterema parametrami. Szablon rozszerza te same parametry, co parametry do wywołania funkcji. Oczekuje się, że wywołanie funkcji zajmie cztery parametry. Przekazywanie pięciu rzeczywistych parametrów do wywołania funkcji, która oczekuje czterech parametrów, jest źle sformułowane. –

Odpowiedz

2

Jak to często bywa, odpowiedź nadeszła kilka godzin po opublikowaniu pytania.

Rozważmy dwie wersje foo:

template<class A, class... Bs, class C> 
void foo1(A, Bs..., C) { } 

template<class A, class C, class... Bs> 
void foo2(A, Bs..., C) { } 

i następujące połączenia (zakładając foo jest foo1 lub foo2)

foo<int,int,int,int>(1,2,3,4,5); 

W przypadku foo1 parametry szablonu są odbierane jako to:

A = int (explicitly provided) 
Bs = {int,int,int} (explicitly provided) 
C = int (deduced) 

Ale w przypadku foo2 one wyglądać tak:

A = int (explicitly provided) 
C = int (explicitly provided) 
Bs = {int,int} (explicitly provided) 

Bs jest w nie wyprowadzona kontekście ([temp.deduct.type]/5.7), więc wszelkie dalsze argumenty funkcji nie może być stosowany w celu rozszerzenia pakietu. Jako taki, foo2 musi mieć jawnie podane wszystkie argumenty szablonu.

+0

Krótka historia: nie rób bałaganu w przypadku niepasujących pakietów szablonów variadic. Chyba, że ​​wiesz, co robisz. Które jest poprawnym stwierdzeniem dla wszystkiego C++. – rubenvb

Powiązane problemy