2013-03-29 13 views
5

Występuje zachowanie o przeciążeniu, które wydaje się bardzo nieoczekiwane. Poniższy kod jest odrzucana z błędem wieloznaczności zarówno przez gcc i brzękiem:Nieoczekiwana rozdzielczość przeciążania z domyślnym parametrem szablonu funkcji

template <typename T> 
struct A 
{ 
    typedef T key_type; 
}; 

template <typename T> 
void foo(A<T> rng, T val); 

template <typename T, typename U = T> 
void foo(T, typename U::key_type); 

int main() 
{ 
    A<int> i; 
    foo(i, 0); 
} 

błędu jest:

test.cpp:16:5: error: call to 'foo' is ambiguous 
    foo(i, 0); 
    ^~~ 
test.cpp:8:6: note: candidate function [with T = int] 
void foo(A<T> rng, T val); 
    ^
test.cpp:11:6: note: candidate function [with T = A<int>, U = A<int>] 
void foo(T, typename U::key_type); 
    ^

Spodziewam się zarówno do dokładnego dopasowania ale pierwszy przeciążenie wygrać w częściowego uporządkowania , ponieważ w pierwszym parametrze A<T> jest bardziej wyspecjalizowany niż T.

Co wieje zdanie jest to, że jeśli zmienię drugi podpis:

template <typename T, typename U = T> 
void foo(T, typename T::key_type); 

zarówno gcc i brzękiem teraz zaakceptować kod i wybierz pierwszy przeciążenie jak bym początkowo spodziewać.

Nie widzę, jak ta zmiana może mieć wpływ na zachowanie: wszystko, co zrobiłem, było zastąpienie użycia parametru szablonu, który nie był ani jednoznacznie określony, ani wydedukowany (U) z jego domyślną wartością (T).

Z drugiej strony zachowanie przed zmianą jest nieoczekiwane, więc może czegoś brakuje.

Może ktoś wyjaśnić:

  1. dlaczego pierwsza sprawa jest niejednoznaczna; i
  2. dlaczego wprowadzona przeze mnie zmiana rozwiązuje niejednoznaczność?

Jeśli jest to istotne, wersje kompilacji, które testowałem, to gcc 4.8.0 i najnowsza kompilacja trunków.

+2

+1, ale dla mnie wygląda to jak prosty błąd kompilatora. Domyślne argumenty szablonu szablonu są nowe. – Potatoswatter

+0

@Potatoswatter: Podejrzewam, że tak samo, ale ponieważ gcc i clang mają identyczne zachowanie, chciałem dokładnie sprawdzić, czy nie jest to pewne zachowanie zgodne z normami, o którym nie wiem, zanim je zgłosiłem. – HighCommander4

+0

Zauważyłem wiele pokrywania się ich błędów, dziwactw i komunikatów diagnostycznych ... bez względu na konsekwencje prawne, nie są to projekty czystych pomieszczeń. – Potatoswatter

Odpowiedz

2

Pytanie dotyczy tego, czy po odjęciu argumentu istnieje lista podstawień wyprowadzonych argumentów szablonu do listy parametrów. W tej fazie domyślne argumenty będą używane dla parametrów szablonu, które nie zostały jeszcze wydedukowane.

Pytanie o to, w jakich kontekstach odliczeń jest wykonywany ten dodatkowy krok, a także o to, czego nie dotyczy aktywny numer podstawowy, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#697.

Jeśli wykonasz ten dodatkowy etap zamiany, musisz również utworzyć instancję szablonów (w przeciwnym razie krok zastępowania nie będzie miał zbyt dużego znaczenia). Możesz także wybrać tylko domyślne argumenty, bez dokonywania zmian, ale w Standardzie te dwie rzeczy idą w parze, więc jako implementator nie wybrałbym tej ścieżki.

Częściowe porządkowanie jest w dużej mierze niezależne od kontekstu, dla którego dokonywane jest częściowe porządkowanie (uwzględniane są niektóre zależności zależne od kontekstu - na przykład parametry funkcji, które nie mają jawnie określonych argumentów wywołania, są ignorowane). Jest także niezależny od tego, czy parametr szablonu miał jawny lub nieowywalny argument szablonu (jeśli więc podałeś wartość U, częściowe zamówienie nie "zapamiętałoby" go.

Clang i GCC nie robią w kroku podstawiania i nie używaj domyślnych argumentów szablonu, więc gdy T jest porównywany z U::key_type, aby dowiedzieć się, U, mówią "huh, nie wydedukowany kontekst. powiemy" sukces, nic do zignorowania! "dla ten parametr ".To samo dzieje się, gdy porównamy T z T::key_type. Porównując inny kierunek, WhatEver::key_type przeciwko T, T może również wydedukować ten typ zależny. Tak więc dla drugiego parametru, w obu twoich próbach oba szablony są co najmniej tak wyspecjalizowane jak siebie nawzajem.

Jednak ważną różnicą jest to, że po odliczeniu muszą być wartości dla wszystkich parametrów używanych na liście typów parametrów.

W większości przypadków, wszystkie parametry szablonu musi mieć wartości w celu odliczenia, aby odnieść sukces, ale dla celów cząstkowych zamawiania parametr szablonu może pozostać bez wartości, pod warunkiem że nie jest stosowane we wszystkich typach wykorzystywane do częściowego uporządkowania. [Uwaga: Parametr szablonu używany w niezorientowanym kontekście jest uważany za użyty. - koniec uwaga]

W swojej drugiej próbie, T została wyprowadzona przez pierwszy parametr, więc nic złego się nie stało po porównań parametrem/typy argumentów zostały zrobione. W pierwszej próbie U pozostawiono niezwiązaną, więc pierwszy szablon nie był uważany za "bardziej wyspecjalizowany" niż drugi w następstwie.