2011-06-29 26 views

Odpowiedz

13

A() daje tymczasowy obiekt A, który nie jest const-kwalifikowany. Wyrażenie A() jest wyrażeniem rvalue, tak, ale to nie czyni warunku konstelacji obiektu A.

Ponieważ obiekt A nie jest const-qualified, niestanowiący operator int() jest dokładnym dopasowaniem, a const operator int() wymaga konwersji kwalifikacji, więc nietrwałe przeciążenie jest wybierane jako najlepsze dopasowanie.

Jeśli ma to być const kwalifikowaną, to trzeba wyraźnie zwrócić const wykwalifikowanych A:

foo(identity<const A>::type()); 

gdzie identity jest zdefiniowany jako

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

pamiętać, że istnieje tak naprawdę nie ma różnicy pomiędzy operator const int() const i operator int() const: wynikiem jest rwartość i tylko wartości rvalue typu klasy mogą być const-kwalifikowane (int nie jest typem klasy).

Należy również zauważyć, że nie ma różnicy między void foo(const int), którą masz i void foo(int). Najwyższe wartości const-qualifiers dla typów parametrów nie mają wpływu na typ funkcji (tj. Typ obu tych deklaracji to void foo(int)). Między innymi dlatego, że dla dzwoniącego nie ma znaczenia, czy istnieje kwalifikator const najwyższego poziomu; musi wykonać kopię niezależnie. Najwyższy poziom const-qualifier wpływa tylko na definicję funkcji.

+0

Nawet 'A' bycie normalnym stosu/sterty przydzielone obiektu (nie tymczasowego), daje taki sam wynik. – iammilind

+0

Jeśli obiekt nie jest const-kwalifikowany, przeciążenie niestałe jest lepiej pasować podczas przeciążania. Czy jest jakiś powód, dla którego można by się tego spodziewać? –

+0

Dlaczego się mylić, nawet jeśli 'foo()' otrzymuje 'const int' i mamy' const :: operator const int() const; ', nadal idzie i wybiera normalny' A :: operator int' . – iammilind

4

Jedna reguła, którą musisz pamiętać o C++: to nigdy bierze pod uwagę wartość, która jest zwracana po wybraniu przeciążenia. W tym przypadku, ponieważ funkcja operator int nie pobiera żadnych parametrów, nie może użyć listy parametrów, aby zawęzić wybór. Wszystko to może użyć stałej obiektu, z którego jest wywoływana. Ponieważ jest to nowy obiekt tymczasowy, nie jest const, więc nie wybiera przeciążenia const.

+1

* Nigdy * nie jest prawdopodobnie zbyt silny, zwracany typ jest brany pod uwagę przy rozwiązywaniu przeciążenia podczas przyjmowania adresu funkcji oraz podczas rozwiązywania operatorów konwersji w celu automatycznej konwersji. (Ta ostatnia może być całkiem przydatna, gdy chcesz mieć funkcję przeciążoną po typie zwracania.) Zwróć serwer proxy z różnymi operatorami konwersji.) –

5

James McNellis ’ Odpowiedź naprawdę zakryła to wszystko, ale nie zaszkodzi (mam nadzieję) z większą ilością wyjaśnień.

So.

Po wywołaniu & hellip;

o.operator int() 

& hellip; wtedy wybór przeciążenia zależy całkowicie od wartości stałej wynoszącej o.

Nic więcej.

Aby zrozumieć, dlaczego należy rozważyć tej klasy:

struct Bar 
{ 
    void f() {} 
    void f() const {} 
}; 

Technicznie te funkcje składowe nie muszą być funkcje składowe. Mogli równie dobrze zostać wybrani do pełnienia funkcji wolnostojących. Ale wtedy muszą Bar argument:

struct Bar 
{}; 

void f(Bar&) {} 
void f(Bar const&) {} 

I mam nadzieję, że teraz łatwiej jest zobaczyć, że kiedy robisz

Bar o; 
f(o); 

wtedy można być wybrana pierwsza funkcja . I tak jest. Ponieważ jeśli wybrano drugą funkcję, nigdy nie można uzyskać pierwszej. Ponieważ jeśli stworzysz obiekt const, to złamie on poprawność, aby wybrać pierwszą. Więc gdy obiekt jest const tylko drugi może być wybrany, a więc, gdy nie jest wybrany, pierwszy.

Krótko mówiąc, jedyną praktyczną alternatywą dla tej reguły byłoby zawsze wybieranie drugiej, co uczyniłoby pierwszą bezużyteczną, tak?

Cheers & HTH.,

+0

Jeśli wersja stała jest niepubliczna, nadal próbuje użyć tej, a nie publicznej wersji const, z wynikiem "błąd dostępu do prywatnego członka"! Tak denerwujące. – Oktalist

Powiązane problemy