5

jestem definiowania wielu przeciążeniem operatora przypisania następująco:Boolean i String Przeciążenie operatora przypisania (C++)

Foo.h

class Foo 
{ 
private: 
    bool my_bool; 
    int my_int; 
    std::string my_string; 
public: 
    Foo& operator= (bool value); 
    Foo& operator= (int value); 
    Foo& operator= (const std::string& value); 
}; 

Foo.cpp

// Assignment Operators. 
Foo& Foo::operator= (bool value) {my_bool = value; return *this;} 
Foo& Foo::operator= (int value) {my_int = value; return *this;} 
Foo& Foo::operator= (const std::string& value) {my_string = value; return *this;} 

A tutaj jest mój main.cpp (patrz komentarz oznaczony SURPRISE):

Foo boolFoo; 
Foo intFoo; 
Foo stringFoo; 

// Reassign values via appropriate assignment operator. 
boolFoo = true;    // works...assigned as bool 
intFoo = 42;     // works...assigned as int 
stringFoo = "i_am_a_string"; // SURPRISE...assigned as bool, not string 

std::string s = "i_am_a_string"; 
stringFoo = s;     // works...assigned as string 

// works...but awkward 
stringFoo = static_cast<std::string>("i_am_a_string"); 

Pytanie: Czy ktoś może mi powiedzieć, dlaczego niecenzuralny ciąg literału jest oceniany w kontekście boolowskim?

+0

@Mooing Duck: Dlaczego usunąć konstruktorów? Dodałem je, aby celowo wskazać, że zmienna może być *** zainicjowana *** za pośrednictwem konstruktora, a następnie *** ponownie przydzielona *** za pośrednictwem operatora przypisania. (Jak widziałem w innych wpisach SO, czasami potrzebujesz *** obydwu ***.) – DavidRR

+2

Poprawiłem kod z powodu [Dobre pytania mają krótki, samodzielny przykład kompilacji] (http://sscce.org/) i [Twój kod może być znacznie krótszy i prostszy, a mimo to nadal powielać problem] (http://ideone.com/W2nemc). Nie przeczytałem większości twojego pytania za pierwszym razem, ponieważ zawierał on zbyt dużo kodu i domyśliłem się (poprawnie), że większość z nich nie była związana z twoim pytaniem. –

+0

@Mooing Duck: Tak, zgadzam się w zasadzie i rozważyłem to podczas dodawania konstruktorów do mojego przykładu. Ale odłożę tu na twój sąd. Mam jednak nadzieję, że każdy, kto natknie się na mój komentarz, będzie wiedział, że powinien wziąć pod uwagę także powiązane czynniki. – DavidRR

Odpowiedz

9

C++ Standard definiuje zasady rozstrzygania przeciążenia w rozdziale 13.3, tam można znaleźć:

13.3.3.2 Ranking ukryte sekwencje konwersji [over.ics.rank]

Przy porównywaniu podstawowe formy niejawnych sekwencji konwersji (jak zdefiniowano w 13.3.3.1)

- standardowa sekwencja konwersji (13.3.3.1.1) jest lepszą sekwencją konwersji niż zdefiniowana przez użytkownika sekwencja konwersji lub sekwencja konwersji elipsy, i zdefiniowana przez użytkownika sekwencja konwersji (13.3.3.1.2) jest lepszą sekwencją konwersji niż sekwencja konwersji elipsy (13.3.3.1.3).

To oznacza, że ​​kompilator będzie preferują standardową sekwencję konwersji z ciągu dosłownym do bool lub int jeśli są dostępne. Teraz, jakie standardowe konwersje są istotne? W twoim przypadku, te dwa są istotne:

4,2 Array do wskaźnika konwersji [conv.array] Tablica

lwartością lub RValue typu „tablica NT” lub” nieznanego ograniczenia T "można przekonwertować na wartość typu" wskaźnik do T ". Wynikiem jest wskaźnik do pierwszego elementu tablicy.

Konwersja zamienia literał łańcuchowy, który jest typu const char[N], na const char*. Drugi oznacza:

4.12 logiczne konwersji [conv.bool]

prvalue arytmetyczne, unscoped wyliczenia wskaźnika lub kursora na typ człon może być przekształcony w prvalue z typ bool. Wartość zerowa, zerowa wartość wskaźnika lub wartość wskaźnika elementu zerowego jest przekształcana na false; każda inna wartość jest konwertowana na true. Wartość produtu typu std::nullptr_t można przekonwertować na wartość prodynkową typu bool; uzyskana wartość to false.

To jest powód, dla którego wskaźnik jest konwertowany na bool. Ponieważ istnieje standardowa sekwencja konwersji, zdefiniowana przez użytkownika konwersja na std::string nie jest używana.

Aby rozwiązać problem, sugeruję dodanie kolejnej przeciążonej wersji, która zajmuje const char* i przekazanie jej dalej do przeciążenia const std::string&.

+0

Dzięki, Daniel! Inną lekcją dla mnie jest to, że literał łańcuchowy literuje do 'char *' (przez 'char [N]'), * nie * 'std :: string'. – DavidRR

+1

@ DavavRR: powinny to być 'const char *' i 'const char [N]', ale yes. –

+0

+1 za cytowanie standardu i objaśnianie go. –

3

Daniel ma rację.

Krótka odpowiedź brzmi, że std::string nie jest typem wbudowanym i jako taki nie ma żadnego magicznego traktowania preferencyjnego. I to, niestety, typ literału łańcuchowego, takiego jak "hi world" jest niestd::string, ale typ wskaźnika, który łatwiej konwertuje do wbudowanego typu bool niż do "zdefiniowanego przez użytkownika" & sztylet; typ std::string.

Zasadniczo odpowiedź brzmi: witamy w C++.

& sztylet; Tak, wiem, to ze standardowej biblioteki i nie, to nie ma znaczenia.

+0

Myślę, że ktoś zajął się przegłosowaniem, ponieważ to ostatnie zdanie uchodzi za trochę złośliwego. –

+2

@Mooing: Jeśli jest snarky, to jest snarky w C++. Jeśli ktoś bierze to osobiście, to jest poza moją pomocą. –

+0

Jako plakat z pytaniami, nie jestem obrażony przez "witamy w C++". Zauważyłem, że C++ zupełnie różni się od Javy i C#. Z C++, z pewnością wydaje się, że jest więcej okazji, aby wpaść w kłopoty ... – DavidRR