2016-12-02 61 views
5

Mam pewne problemy ze zrozumieniem warunków, w których C++ będzie używać niejawnej konwersji. Załóżmy, że mam klasę:Konwersje niejawne C++ w operandach dla standardowych operatorów

class SomeClass 
{ 
private: 
    int val; 
public: 
    SomeClass(int i) :val{ i } {} 
    operator string() { return to_string(val); } 
}; 

Dlaczego podczas używania tej klasy z operatorami muszę rzutować na ciąg? Dlaczego po prostu nie wykonuje on konwersji domyślnie? Kod

:

int main(void) 
{ 
    SomeClass sc = 4; 
    cout << (string)sc << endl; //prints 4, compiles fine 
    cout << sc << endl;//does not compile, no operator "<<" matches these operands 

    string str1 = sc;//compiles fine, performs cast 
    string str2 = "Base String" + sc;//does not compile, no operator "+" matches these operands 
} 

To pytanie jest bardziej akademicki niż praktyczny, jak tylko za pomocą obsady jest bardziej czytelny w każdym razie.

Odpowiedz

2

operator<< overload że przyzwyczaja kiedy piszesz cout << (string)sc jest szablonem funkcji:

template <class CharT, class Traits, class Allocator> 
std::basic_ostream<CharT, Traits>& 
    operator<<(std::basic_ostream<CharT, Traits>& os, 
       const std::basic_string<CharT, Traits, Allocator>& str); 

To dlatego std::string sama jest szablon klasy i może być tworzony z innych typów niż char i powinny nadal być drukowane, jeśli znaki są zapisywane w strumieniu tego samego rodzaju znaków. W rzeczywistości dokładnie tak jest z std::wstring, gdzie CharT jest wchar_t, a nie char. To samo działa operator<<, pod warunkiem, że używasz odpowiedniego strumienia.

Podczas pisania cout << sc uwzględniane jest to konkretne przeciążenie. To przeciążenie jest następnie odrzucane, ponieważ kompilator nie może wywnioskować, jakiego typu użyć dla CharT i innych. Mogłaby ona wywnioskować typ tylko wtedy, gdyby wiedział już, że konwersja zostanie przeprowadzona, ale konwersje nie są jeszcze brane pod uwagę, zostaną one sprawdzone tylko nieco później.

Jeśli wystąpiło nie-szablonowe przeciążenie, które trwało std::string, to by działało, sc zostałoby niejawnie skonwertowane.

+0

Zatem, aby być bardziej zgodnym ze standardowymi funkcjami biblioteki C++ (bez rzutowania), powinienem pisać niejawne konwersje na 'basic_string', a nie na string? –

+0

@ApoorvaKharche Nie, 'string' jest typedef dla jednej konkretnej instancji' basic_string'. To, czy 'operator <<' jest napisany w terminach 'basic_string ' lub w terminach 'string' nie ma znaczenia, ponieważ oznaczają dokładnie to samo. Określa, czy 'operator <<' jest zapisany w terminach 'basic_string ' lub 'basic_string ', gdzie 'T' ma być wyprowadzone, robi różnicę i nie masz nad tym kontroli nad własnymi klasami. – hvd

2

std::cout nie przyjmuje numeru std::string.
Przyjmuje szablonowy kod std::basic_string, którego parametry należy wyprowadzić.
Aby uzyskać więcej informacji, patrz here.

Rozważmy następujący przykład:

#include<string> 

struct SomeClass { 
    operator std::string() { return ""; } 
}; 

template <class CharT, class Traits, class Allocator> 
void f(const std::basic_string<CharT, Traits, Allocator> &) {} 

template <class CharT, class Traits, class Allocator> 
void f(std::basic_string<CharT, Traits, Allocator> &) {} 

int main(void) { 
    SomeClass sc{}; 
    f((std::string)sc); 
    //f(sc); 
} 

Jest ona podobna do tego, co dzieje się w Twoim przypadku.
Oczywiście, f(sc) nie kompiluje się z prawie tego samego powodu.

Problem polega na tym, że do wyprowadzenia parametrów szablonu SomeClass należy przekonwertować na std::string. Aby móc przekonwertować go na std::string, kompilator powinien odgadnąć, że istnieje przeciążenie i spróbować go użyć. Tak czy inaczej, taka realna funkcja nie istnieje z jej punktu widzenia, ponieważ parametry szablonu nadal muszą zostać wydedukowane i wydedukowanie ich kompilator powinien odgadnąć, że przeciążenie dla SomeClass istnieje po rzutowaniu. Nie może, ponieważ ... I tak dalej.

Nie sprawdziłem, ale założę się, że coś podobnego ma również zastosowanie do operator+.

+0

Co dokładnie należy rozumieć? – skypjack

+0

Więc, aby być bardziej zgodnym ze standardowymi funkcjami biblioteki C++ (bez rzutowania), powinienem pisać niejawne konwersje na 'basic_string', a nie na stringach? –

+0

Krótko po tej odpowiedzi, historia edycji sprawiała, że ​​wyglądała tak, jakbyś skopiowała moje, ale historia edycji była myląca. Opublikowaliście złą odpowiedź, usunęli ją, gdy się zorientowaliście, i w końcu ją naprawiliście. W końcu po prostu napisaliśmy zasadniczo tę samą odpowiedź w tym samym czasie. Jeśli to powinno być powodem, dla którego ktoś go zignorował, pozwól, aby ta osoba odwróciła sprawę. – hvd