5

Visual C++ 2012. Kod. Myślę, że powinien się skompilować; kompilator z szacunkiem nie zgadza się. Zawęziłem moją repro do:Nieoczekiwanie niejednoznaczna rozdzielczość przeciążania w VC++ 2012

struct B { }; 

void foo(B* b, signed int si) { } // Overload 1 
void foo(B const* b, unsigned int ui) { } // Overload 2 

int main() 
{ 
    B b; 
    unsigned int ui; 
    foo(&b, ui); 
} 

Mamy więc dwóch kandydatów do rozwiązania problemu przeciążenia. Przy pierwszym przeciążeniu pierwszy argument dokładnie pasuje, a drugi argument wymaga całkowitej konwersji (niepodpisany do podpisu). W przypadku drugiego przeciążenia drugi argument dokładnie się zgadza, a pierwszy argument wymaga korekty cv (ponieważ &b jest wskaźnikiem na niestanowiący).

Teraz wydaje się, że powinno to być całkowicie jednoznaczne. W przypadku Przeciążenia 1, pierwszym argumentem jest "Dopasowanie ścisłe" zdefiniowane w sekcji standardowej dotyczącej rozdzielczości przeciążenia, ale drugie jest "Konwersją". W przypadku Overload 2 oba argumenty to "Exact Matches" (konwersja kwalifikacji ma tę samą wartość co tożsamość). Dlatego (moje najwyraźniej niedoskonałe rozumowanie idzie), należy wybrać Overload 2, bez dwuznaczności. I jeszcze:

a.cpp(12): error C2666: 'foo' : 2 overloads have similar conversions 
    a.cpp(6): could be 'void foo(const B *,unsigned int)' 
    a.cpp(5): or  'void foo(B *,int)' 
    while trying to match the argument list '(B *, unsigned int)' 
    note: qualification adjustment (const/volatile) may be causing the ambiguity 

GCC wydaje się dobrze z kodem, zarówno w domyślnym dialekcie aw C++ 11 (dzięki, IDEOne!). Więc jestem skłonny skryć to do błędu w MSVC, ale (a) wiesz, co mówią o ludziach, którzy myślą, że ich błędy są kompilatorami, i (b) wygląda na to, że byłby to dość oczywisty błąd , rodzaj, który wysłałby czerwone flagi podczas testów zgodności.

Czy jest to niezgodny MSVC, czy niezgodny z GCC? (Albo jedno i drugie?) Czy moje rozumowanie dotyczące rozdzielczości przeciążenia brzmi?

+1

Nie wiem, który kompilator jest poprawny, ale jako człowiek wolę wiedzieć, które przeciążenie będzie używane bez konieczności ujednoznaczniania w oparciu o "pierwszeństwo" dwóch typów konwersji :-) – Cameron

+0

@Cameron Oh, I Zgodzić się. Rzeczywisty przypadek użycia ma dużo więcej sensu i naprawdę * wygląda * jednoznacznie. – Sneftel

Odpowiedz

7

MSVC jest poprawny.

gcc 4.9.0 mówi:

ostrzeżenie: ISO C++ mówi, że są niejednoznaczne, chociaż najgorsze konwersji pierwszy jest lepszy niż najgorszy nawrócenia drugi: [domyślnie włączona]

clang 3.4.1 zgadza się, że obie funkcje są niejednoznaczne.

Chociaż B* => B* i B* => B const* oba mają dokładne dopasowanie rangi, były jeszcze lepsze sekwencja konwersja za over.ics.rank/3; to jest (na przykład) w celu zapewnienia, że:

int f(const int *); 
int f(int *); 
int i; 
int j = f(&i); // calls f(int*) 

Z over.ics.rank/3:

standardową sekwencję konwersji S1 lepszą konwersję niż kolejność standardową sekwencję konwersji S2, jeżeli [.. .]
- S1 i S2 różnią się tylko konwersją ich kwalifikacji i dają podobne typy odpowiednio T1 i T2 (4.4), a sygnatura kwalifikacyjna cv typu T1 jest prawidłowym podzbiorem sygnatury kwalifikacyjnej cv typu T2. [...]

I, oczywiście, unsigned int => unsigned int jest lepszy niż unsigned int => signed int. Tak więc z dwóch przeciążeń, jeden ma lepszą niejawną sekwencję konwersji na pierwszym argumencie, a drugi ma lepszą niejawną sekwencję konwersji na drugim argumencie. Więc nie można ich odróżnić za pośrednictwem over.match.best/1.

+0

Dzięki. Więc jaka jest wada mojego rozumowania? Z mojego odczytu Standardu wynika, że ​​nie ma konwersji na przeciążenie 2, które jest gorsze niż odpowiednia konwersja dla przeciążenia 1 - że kompilator nie powinien preferować 'B *' do 'B const *' podczas porównywania przeciążeń. – Sneftel

+0

@Sneftel ah, ale tak - dodam dokładną treść. – ecatmur

+0

Yeh, właśnie to znalazłem. Wygląda na to, że przestałem czytać zbyt wcześnie. Dzięki za kopanie. – Sneftel

Powiązane problemy