10

Im folgenden Stück Code (live on coliru):Implizite Konvertierung Operator Priorität

#include <iostream> 
#include <string> 

int main() 
{ 
    struct S { 
     operator bool  () const { return false; } 
     operator std::string() const { return "false"; } 
    } s; 
    std::cout << s << "\n"; // outputs 0 
} 

Wie funktioniert der Compiler wählen die implizite Konvertierung in bool über std::string zu holen?

Meine Hypothese ist, dass es in diesem Fall möglicherweise die Reihenfolge der Erklärung der verschiedenen Geschmacksrichtungen von ist, aber ist es alles? Sagt der Standard etwas über die Auswahl einer spezifischen impliziten Konvertierung?

+2

Nur nitpick wird nichts jemals implizit gegossen.Typen werden implizit konvertiert, aber ein * Cast * bedeutet * explizite Konvertierung *. – StoryTeller

+0

@StoryTeller Danke, es ist gut, die spezifische Terminologie zu kennen. Ich habe meine Frage bearbeitet. – YSC

Antwort

10

Erinnern Sie sich, dass std::string ist kein eigenständiger Typ, es ist wirklich eine Klassenvorlage Spezialisierung - std::basic_string<char>. Das sehr wichtige Detail ist, dass die potenzielle Überlastung für ein std::string Streaming nimmt kein std::string const& Argument, es ist ein function template ist, die einen std::basic_string const& folgert:

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); 

Template Abzug hält nie Konvertierungen. Die Namenssuche findet diese Funktionsvorlage und verwirft sie dann als nicht lebensfähig aufgrund eines Fehlschlags. S ist kein basic_string<CharT, Traits, Allocator> für solche Typen, also sind wir fertig. Die einzigen brauchbaren Stream-Operatoren wären alle integralen, von denen bool die beste Übereinstimmung ist.

Wenn es speziell eine Funktion mit der Unterschrift:

std::ostream& operator<<(std::ostream&, std::string const&);  

Dann würde der Anruf nicht eindeutig sein - würden Sie zwei benutzerdefinierte Konvertierungen erhalten, die gewählt wird, in äquivalenter Weise würde.


Dies ist einfach durch die Verwendung unserer eigenen Funktionen anstatt die Millionen Überlastungen für operator<< zu überprüfen:

void foo(bool); // #1 
void foo(std::string); // #2 

void bar(bool); // #3 
template <class C, class T, class A> 
void bar(std::basic_string<C,T,A>); // #4 

foo(S{}); // error: ambiguous 
bar(S{}); // calls #3 
+0

@YSC: Ich habe meine bearbeitet, um es zu korrigieren. Ich hatte damals nicht bemerkt, dass es jetzt eine unvollkommene Version von Barry ist. Ich habe es immer noch verlassen, weil ich denke, dass der Ratschlag "tue das nicht, dann" nützlich ist. –

+0

@Barry, Abzug gelingt für Vorlagenoperator <<. Der Compiler wählt die Elementfunktion, weil es keine Vorlage ist. Siehe meine Antwort. – Oliv

+0

Eine klare Möglichkeit, dies für OP zu sehen, ist 'operator bool' aus dem ursprünglichen Code auszukommentieren ... dann kann es nicht kompiliert werden (es heißt nicht den String-Konverter) –

2
ostream& operator<<(bool value); 

Ist eine Mitgliedsfunktion von std::ostream. Auf der anderen Seite:

std::ostream& operator<<(std::ostream& os, const std::string& str); 

ist eine eigenständige Funktion - , die tatsächlich als Vorlage deklariert wird. Ein Verweis auf S stimmt mit keiner der Vorlagen überein - daher wird dies nicht für die Vorlagenerweiterung berücksichtigt.


Es ist möglich, eindeutig zu bestimmen, welche Überlastung gewählt werden sollte, aber ich schlage vor, Sie tun das nicht.

a) Dies ist immer eine der kniffligen Ecken des Standard (so können Sie Compiler-Fehler auftreten;

b) künftige Entwickler immer den Code schwer zu lesen.

Mein Vorschlag ist, das Problem vollständig zu vermeiden, indem Sie einfach Ihre Konvertierungsoperatoren explizit machen, oder geben Sie ihnen Namen wie to_bool() und to_string().

+2

Mitglied/Nichtmitglied ist irrelevant. Es ist die Schablonenhaftigkeit, die das Problem ist. –

+0

Ich stimme Ihrer Schlussfolgerung zu (bevorzugen Sie explizite Conversions), aber ich bin mir Ihrer Erklärung nicht ganz sicher. Siehe [dieses Beispiel auf coliru] (http://coliru.stacked-crooked.com/a/174a94a1e2fdcb7e). – YSC

+0

@ T.C. Ah-ha! Vielen Dank. –