2015-09-01 8 views
10

Rozważmy następujący:Niejednoznaczne wezwanie do przeładowania szablonów funkcji - nawet jeśli jest się bardziej wyspecjalizowanym?

#include <utility> 

template <int N> 
using size_ = std::integral_constant<int, N>; 

template <int From> 
void f(size_<From>, size_<From+1>) // (1) 
{ } 

template <int From, int To> // (2) 
void f(size_<From>, size_<To>) 
{ } 

int main() 
{ 
    f(size_<0>{}, size_<1>{}); 
} 

Zarówno gcc i raport dzyń wezwanie jako niejednoznaczne. Czemu? Czy nie jest bardziej wyspecjalizowany niż (1) niż (2)?

Uwaga: Wiem, że można to łatwo naprawić za pomocą dodatkowego enable_if_t<(To > From+1)> wrzuconego do (2), ale nie sądziłem, że muszę to zrobić.

+4

Czy nie dlatego 'From + 1 'nie jest wywnioskować, stąd sama odliczenie * * gdy uda weryfikowane przed pewnymi unikalnymi wartościami jak' size_ {}, size_ {} 'generowane przed przeciążeniem (2)? –

+0

@ Piotrotknicki §14.8.2.4/11: "W większości przypadków wszystkie parametry szablonu muszą mieć wartości, aby odliczenie mogło się powieść, ale dla częściowego celu zamówienia parametr szablonu może pozostać bez wartości pod warunkiem, że nie jest używany w typach używane do częściowego porządkowania. [* Uwaga *: ** Parametr szablonu używany w niezorientowanym kontekście jest uważany za użyty. ** - * końcowy przypis *) " – Columbo

Odpowiedz

3

To było - nic dziwnego - skierowana przez podobny przykład w CWG problem, mianowicie #455:

W przypadku, gdy jeden z argumentów nie jest przeklęty następnie częściowe zamawiania należy brać pod uwagę tylko ten typ z specjalność:

template<typename T> struct B { typedef T type; }; 

template<typename T> char* f3(T, T);     // #7 
template<typename T> long* f3(T, typename B<T>::type); // #8 

char* p3 = f3(p3, p3); // #9 

Według mojego rozumowania # 9 powinna przynieść niejasności, ponieważ druga para jest (T, długo *). Drugi typ (tj. Długi *) został pobrany z kandydata specjalizacyjnego nr 8 na . EDG i GCC zaakceptowały kod. VC i BCC stwierdził dwuznaczność.

Zarówno ICC, jak i VC++ skompilują twój kod. Zgodnie z obecnym brzmieniem są one poprawne: Każda para jest obsługiwana niezależnie, a jako size_<From+1> powoduje, że From pojawia się w niezorientowanym kontekście ([temp.deduct.type]/(5.3)), odliczenie koniecznie nie powiedzie się, a zatem size_<From+1> jest co najmniej tak wyspecjalizowany jak size_<To>, ale nie na odwrót. Zatem przeciążenie (1) jest bardziej wyspecjalizowane niż (2).

Więc ICC i VC++ (prawdopodobnie) przetwarzają każdą parę odliczeń i wyciągają wniosek, że dla drugiej z nich size_<To> nie jest tak wyspecjalizowana jak size_<From+1>.
Clang i GCC (przypuszczalnie) twierdzą, że dla (1), From jest wyprowadzony z pierwszego argumentu, a zatem nie musi być wyprowadzony w drugiej parze dla size_<To>, aby być na poziomie tak wyspecjalizowanym jak jego odpowiednik.

+0

Z perspektywy czasu ten przykład nie ma wiele wspólnego z przykładem pytanie ... – Columbo

+0

Więc mówisz, że gcc/clang są złe? – Barry

+0

@ Barry Powiedziałbym tak, tak. Zdziwiłbym się, gdyby nie. – Columbo

Powiązane problemy