Krótki
Funkcja konwersji operator int()
jest wybierana przez clang over, operator bool() const
ponieważ b
nie jest kwalifikowana jako const, podczas gdy operator konwersji dla bool to.
Krótki rozumowanie jest to, że funkcje kandydujących dla rozdzielczości przeciążenia (z utajonego parametru obiektu w miejscu), do konwersji b
do bool
są
operator bool (B2 const &);
operator int (B2 &);
gdzie drugi jest lepiej dopasowany, ponieważ b
nie jest określony jako const.
Jeśli obie funkcje mają tę samą kwalifikację (obie const
lub nie), operator bool
jest wybierana, ponieważ zapewnia bezpośrednią konwersję.
Konwersja za pomocą notacji rzutowej, analizowana krok po kroku
Jeśli zgodzimy się, że boolean ostream inserter (std :: basic_ostream :: operator << (bool val) zgodnie z [ostream.inserters.arithmetic]) jest wywoływany z wartością wynikającą z konwersji b
na bool
to możemy wykopać się do tej konwersji .
1. Wyrażenie obsady
Obsada b do bool
(bool)b
ocenia do
static_cast<bool>(b)
zgodnie z C ++ 11, 5.4 / 4 [wyraż.cast], ponieważ const_cast
nie ma zastosowania (nie można tu dodawać ani usuwać stałej).
Ta statyczna konwersja jest dozwolona według C ++ 11, 5.2.9 / 4 [expr.static.cast] , jeśli bool t(b);
dla wymyślonej zmiennej t jest dobrze sformułowana. Takie instrukcje nazywane są bezpośrednią inicjalizacją zgodnie z C ++ 11, 8.5 / 15 [dcl.init] .
2. Inicjalizacja bezpośrednia bool t(b);
Klauzula 16 najmniej wymienionego standardowego akapitu stwierdza (moje wyróżnienie):
Semantyka inicjatorów jest następująca. Typ docelowy to typ inicjowanego obiektu lub odwołania, a typ źródłowy to typ wyrażenia inicjatora.
[…]
[...] jeśli typ źródła jest (prawdopodobnie kwalifikowany przez cv) typem klasy, uwzględniane są funkcje konwersji .
Odpowiednie funkcje konwersji są wyliczane, a najlepsza jest wybierana poprzez rozpoznawanie przeciążenia.
2.1 Jakie funkcje konwersji są dostępne?
Dostępne funkcje konwersji to, operator int ()
a operator bool() const
ponieważ C ++ 11, 12.3 / 5 [class.conv] mówi nam:
Funkcja konwersji w klasie pochodnej nie ukrywa funkcji konwersji w klasie bazowej, chyba że dwie funkcje są konwertowane na ten sam typ.
Podczas gdy C ++ 11, 13.3.1.5/1 [over.match.conv] stwierdza:
Uwzględniono funkcje konwersji S i jego klas bazowych.
gdzie S jest klasą, z której zostanie przekonwertowana.
2.2 Które funkcje konwersji mają zastosowanie?
C ++ 11, 13.3.1.5/1 [over.match.conv] (moje podkreślenie):
1 [...] Zakładając, że „cv1 T” jest typem inicjowanego obiektu, a „cv S” jest typem wyrażenia inicjatora, przy czym S jest typem klasy, funkcje kandydatów są wybierane w następujący sposób: Konwersja rozważane są funkcje S i jego klas bazowych. Te niejawne funkcje konwersji, które nie są ukryte w S i dają typ T lub typ, który można przekonwertować na typ T za pomocą standardowej sekwencji konwersji, są funkcjami kandydującymi.
Dlatego operator bool () const
ma zastosowanie, ponieważ nie jest ukryty w B2
środku i daje bool
.
Część z naciskiem w ostatnim cytacie standardowym ma znaczenie dla konwersji przy użyciu, operator int ()
ponieważ int
jest typem, który można przekonwertować na bool za pomocą standardowej sekwencji konwersji. Konwersja z int
na bool
nie jest nawet sekwencją, ale zwykłą konwersją bezpośrednią, która jest dozwolona w C ++ 11, 4.12 / 1 [conv.bool]
Wartość pr arytmetycznego, wyliczenia bez zakresu, wskaźnika lub wskaźnika do typu elementu członkowskiego można przekonwertować na prvalue typu bool. Wartość zerowa, pusta wartość wskaźnika lub pusta wartość wskaźnika elementu członkowskiego jest konwertowana na fałsz; każda inna wartość jest konwertowana na prawdę.
Oznacza to, że operator int ()
ma to również zastosowanie.
2.3 Która funkcja konwersji jest wybrana?
Wybór odpowiedniej funkcji konwersji odbywa się poprzez rozwiązanie przeciążenia ( C ++ 11, 13.3.1.5/1 [over.match.conv] ):
Rozdzielczość przeciążenia służy do wybierania funkcji konwersji do wywołania.
Istnieje jeden specjalny „dziwactwo”, jeśli chodzi o rozwiązywanie przeciążeń funkcji składowych klasy: niejawny parametr obiektu ”.
Per C ++ 11, 13.3.1 [over.match.funcs] ,
[...] zarówno statyczne, jak i niestatyczne funkcje składowe mają niejawny parametr obiektu [...]
gdzie typ tego parametru dla niestatycznych funkcji składowych - zgodnie z klauzulą 4 - to:
gdzie X to klasa, której składową jest funkcja, a cv to kwalifikacja cv na deklaracji funkcji składowej.
Oznacza to, że (na C ++ 11, 13.3.1.5/2 [over.match.conv] ), podczas inicjalizacji przez funkcję konwersji,
Lista argumentów ma jeden argument, którym jest wyrażenie inicjalizujące. [Uwaga: ten argument zostanie porównany z niejawnym parametrem obiektu funkcji konwersji. —End note]
Kandydujące funkcje do rozwiązywania problemów z przeciążeniem to:
operator bool (B2 const &);
operator int (B2 &);
Oczywiście operator int ()
jest to lepsze dopasowanie, jeśli zażądano konwersji przy użyciu niestałego obiektu typu, B2
ponieważ operator bool ()
wymagana jest konwersja kwalifikacji.
Jeśli obie funkcje konwersji mają tę samą kwalifikację const, rozwiązanie przeciążenia tych funkcji już nie wystarczy. W takim przypadku ma miejsce ranking konwersji (kolejności).
3. Dlaczego jest operator bool ()
wybierany, skoro obie funkcje konwersji mają tę samą kwalifikację const?
Konwersja z B2
do bool
jest sekwencją konwersji zdefiniowaną przez użytkownika ( C ++ 11, 13.3.3.1.2 / 1 [over.ics.user] )
Sekwencja konwersji zdefiniowana przez użytkownika składa się z początkowej sekwencji konwersji standardowej, po której następuje konwersja zdefiniowana przez użytkownika, po której następuje druga standardowa sekwencja konwersji.
[...] Jeśli konwersja zdefiniowana przez użytkownika jest określona przez funkcję konwersji, początkowa standardowa sekwencja konwersji przekształca typ źródłowy na niejawny parametr obiektu funkcji konwersji.
C ++ 11, 13.3.3.2/3 [over.ics.rank]
[...] definiuje częściowe uporządkowanie niejawnych sekwencji konwersji na podstawie relacji lepsza sekwencja konwersji i lepsza konwersja.
[...] Zdefiniowana przez użytkownika sekwencja konwersji U1 jest lepszą sekwencją konwersji niż inna zdefiniowana przez użytkownika sekwencja konwersji U2, jeśli zawiera tę samą zdefiniowaną przez użytkownika funkcję konwersji lub konstruktora lub inicjalizację agregatu, a druga standardowa sekwencja konwersji U1 jest lepsza niż druga standardowa sekwencja konwersji U2.
Drugi średnia konwersji przypadku operator bool()
jest bool
do bool
(konwersja tożsamości), podczas gdy drugi standard konwersji w przypadku operator int ()
jest int
do bool
których to logiczna konwersji.
Dlatego sekwencja konwersji przy użyciu operator bool ()
jest lepsza, jeśli obie funkcje konwersji mają tę samą kwalifikację const.