Frage

Als Lernübung, ich habe mich an, wie die automatische Typ-Konvertierung funktioniert in C ++. I wissen , dass die automatische Typumwandlung sollte generell vermieden werden, aber ich möchte meine Kenntnisse in C ++ erhöhen, indem das Verständnis, wie es funktioniert trotzdem.

Ich habe eine StdStringConverter Klasse erstellt, die automatisch zu einem std::string umgewandelt werden können, aber der Compiler (g ++ 4.3.4 auf Debian) scheint nicht um die Konvertierung zu tun, wenn das Objekt gegen einen echten std::string verglichen (ignorieren Sie den Mangel an passing by-reference und unnötige Erzeugung von temporären Objekten):

#include <string>

class StdStringConverter
{
public:
    explicit StdStringConverter(std::string name) : m_name(name) {}
    operator const std::string () const { return m_name; }
private:
    std::string m_name;
};

int main()
{
    StdStringConverter converter(std::string("Me"));
    const std::string name = "Me";
    // Next line causes compiler error:
    // no match for 'operator==' in 'converter == name'
    return (converter == name) ? 0 : 1;
}

Auf der anderen Seite, wenn ich es leicht zu einer CStringConverter Klasse zu ändern, die automatische Konvertierung hat stattfinden, obwohl verglichen char Zeiger wahrscheinlich nicht das, was ich gedacht:

#include <string>

class CStringConverter
{
public:
    explicit CStringConverter(std::string name) : m_name(name) {}
    operator const char* () const { return m_name.c_str(); }
private:
    std::string m_name;
};

int main()
{
    CStringConverter converter(std::string("Me"));
    const char* name = "Me";
    // Next line compiles fine, but they are not equal because the
    // pointers don't match.
    return (converter == name) ? 0 : 1;
}

Gibt es etwas Besonderes über den Unterschied zwischen einem std::string und einem char* in diesem Zusammenhang, dass der Compiler nicht behandeln sie die gleiche macht?

War es hilfreich?

Lösung

Das Problem ist, aufgrund der Tatsache, std :: string ist eigentlich eine Instanz der Klasse Template std :: basic_string. Ein Operator ==, die im Namensraum std dauert zwei std :: basic_string Vorlagen zur Verfügung:


template<class charT, class traits, class Allocator>
bool operator==(const basic_string& lhs,
                const basic_string& rhs);

Wenn diese Version von operator == überlastet wurde speziell auf std :: string, würde den Code in Ordnung sein. Aber das ist nicht der Fall ist, die den Compiler erfordern würde Vorlage Argument Abzug auf den Template-Parameter von std :: basic_string auszuführen, so es, dass die Rückkehr der Conversion-Betreiber verstehen könnte eine mögliche Übereinstimmung vorhanden ist.

Allerdings wird der Compiler das nicht tun. Ich weiß nicht, welchen Teil des Standard besagt genau dies. Aber die allgemeine Idee ist, dass solche Umwandlungen arbeiten nur für Nicht-Template-Typen.

Eine Sache, die ich vorschlagen kann, ist für Sie StdStringConverter in einem Namensraum zu platzieren und eine Version von operator == für std :: string liefern in diesem Namensraum. Auf diese Weise, wenn Ihr Compiler einen Ausdruck wie die ADL (Argument abhängige Lookup) finden kommt ins Spiel, und alles funktioniert.


#include <string>

namespace n1 {

class StdStringConverter
{
public:
    explicit StdStringConverter(std::string name) : m_name(name) {}
    operator std::string () { return m_name; }
private:
    std::string m_name;
};

bool operator==(std::string const& a, std::string const& b)
{
  return a == b; //EDIT: See Paul's comment on std::operator== here.
}

}

int main()
{
    using namespace n1;
    StdStringConverter converter(std::string("Me"));
    std::string name = "Me";
    return (converter == name) ? 0 : 1;   
}

Andere Tipps

Im ersten Beispiel die beiden verglichenen Klassen (string und StdStringConverter) erhalten keine spezielle Behandlung vom Compiler für Typ zu konvertieren. Das bedeutet, dass der Betreiber Überlastung Sie nicht einmal gemacht hat ausgelöst werden. Der Compiler sieht durch die Liste des Operators == Überlastungen und nicht von ihnen in einem StdStringConverter nehmen, damit es bei Ihnen brüllt.

Im zweiten Beispiel ist der Name * char. Da es sich um eine primitive Art ist dann versucht der Compiler * die nicht primitiv bis auf einen char zu konvertieren. Da Sie eine Überschreibung an der richtigen Stelle funktioniert es und Sie vergleichen Adressen.

Der Compiler wird nicht explizite Typumwandlung auf Operationen, die nicht enthalten primitive Typen. Etwas wird es tun, ist versucht, Konstrukteuren zu verwenden, um die Typen übereinstimmen. Zum Beispiel, wenn Sie Ihr erstes Beispiel das ändern:

#include <string>

class StdStringConverter
{
public:
    StdStringConverter(std::string name) : m_name(name) {}
    bool operator==(const StdStringConverter &name) { return m_name == name.m_name; }
    operator const std::string () const { return m_name; }
private:
    std::string m_name;
};

int main()
{
    StdStringConverter converter(std::string("Me"));
    const std::string name = "Me";
    // Next line causes compiler error:
    // no match for 'operator==' in 'converter == name'
    return (converter == name) ? 0 : 1;
}

Jetzt kehrt das Programm 0. Da der Konstruktor jetzt nicht explizit der Compiler wird versuchen, es zu verwenden, um die Zeichenfolge in eine StdStringConverter zu konvertieren. Da gibt es nun einen Operator == in den StdStringConverter alles funktioniert.

Es gibt mehrere Faktoren. Wenn Sie die Anweisung return thusly ändern

return (std :: operator == (Name, Name))? 0: 1;

es kompiliert, obwohl es offensichtlich nicht das Gleiche tut. Auf der anderen Seite

return (std :: operator == (Konverter, Name))? 0: 1;

nicht aber eine interessante Fehlermeldung

keine passende Funktion für Aufruf von ‚operator == (StdStringConverter &, const std :: string &)

, die mir diesen Operator erinnert == wird als Templat auf basic_string <>, die drei Template-Parameter hat zu booten. Wenn Sie int in Ihrem Beispiel, anstatt std :: string verwenden, wird der Compiler nicht beklagen.

Wie die gewünschte Wirkung mit std :: string zu erhalten, ist interessanter ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top