Frage

Wenn Sie eine Klasse zu schreiben als Wrapper zu handeln um ein Heap-Objekt zugewiesen, ich habe ein Problem mit impliziter Typumwandlung festgestellt, die auf dieses einfache Beispiel reduziert werden kann.

Im Code unter der Wrapper-Klasse verwaltet einen Heap-Objekt zugewiesen und konvertiert implizit in einen Verweis auf dieses Objekt. Dies ermöglicht es dem Wrapper-Objekt als Argument an die Funktion Schreib weitergeleitet werden (...), da implizite Konvertierung stattfindet.

Der Compiler fehlschlägt, aber wenn man versucht, den Anruf zu Bediener zu lösen << (...), es sei denn, eine explizite Umwandlung vorgenommen wird (markiert mit MSVC8.0, Intel 9.1 und gcc 4.2.1 Compiler).

Also, (1) warum die implizite Konvertierung in diesem Fall fehlschlagen? (2) könnte es zu Argument abhängige Lookup in Beziehung gesetzt werden? und (3) ist es etwas, das getan werden kann, um diese Arbeit zu machen, ohne die explizite Umwandlung?

#include <fstream>

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

void write(std::ostream& os)
{
    os << "(1) Hello, world!\n";
}

int main()
{
    wrapper<std::ostream> file(new std::ofstream("test.txt"));

    write(file);
    static_cast<std::ostream&>( file ) << "(2) Hello, world!\n";
    // file << "(3) This line doesn't compile!\n";
}
War es hilfreich?

Lösung

Es schlägt fehl, weil Sie versuchen, einen Operator Ihrer wrapper<T> Klasse zu lösen, die nicht existiert. Wenn Sie es ohne die Darsteller arbeiten möchten, können Sie so etwas wie dies zusammen:

template<typename X> wrapper<T> &operator <<(X &param) const {
    return t << param;
}

Leider weiß ich nicht, einen Weg, den Rückgabetyp bei der Kompilierung zu lösen. Zum Glück in den meisten Fällen ist es die gleiche Art wie das Objekt, auch in diesem Fall mit ostream.

EDIT: Modifizierte Code durch Anregung von Strich-tom-Knall. Geänderte Rückgabetyp wrapper<T> &.

Andere Tipps

Der Compiler nicht genügend Kontext, dass operator& zu bestimmen, wird eine gültige Konvertierung machen. Also, ja, ich glaube, dies Argument abhängige Nachschlag verwandt ist: Der Compiler für eine operator<< sucht, die eine nicht-const wrapper<std::ostream> als ersten Parameter akzeptieren

.

Ich denke, das Problem mit der Aufrechterhaltung einiger Kompilierung-Einschränkungen zu tun hat. In Ihrem Beispiel würden die Compiler zuerst finden müssen alle die möglichen Betreiber <<. Dann wird für jeden von ihnen, sollte es versuchen, wenn Ihr Objekt automatisch konvertiert werden (direkt oder indirekt) zu einem der Typen, die jeder Operator << der Lage sind, zu übernehmen.

Dieser Test kann sehr komplex sein, und ich denke, dies ist eine vernünftige Compilierung Zeit zur Verfügung zu stellen beschränkt ist.

Nach einigen Tests, ein noch einfacheres Beispiel identifiziert die Quelle des Problems. Der Compiler kann nicht das Template-Argument T in f2(const bar<T>&) ableiten unterhalb von impliziter Umwandlung von wrapper<bar<int> > zu bar<int>&.

template <typename T>
class wrapper
{
    T* t;
  public:
    explicit wrapper(T * const p) : t(p) { }
    ~wrapper() { delete t; }
    operator T & () const { return *t; }
};

class foo { };

template <typename T> class bar { };

void f1(const foo& s) { }
template <typename T> void f2(const bar<T>& s) { }
void f3(const bar<int>& s) { }

int main()
{
    wrapper<foo> s1(new foo());
    f1(s1);

    wrapper<bar<int> > s2(new bar<int>());
    //f2(s2); // FAILS
    f2<int>(s2); // OK
    f3(s2);
}

Im ursprünglichen Beispiel std::ostream ist eigentlich ein typedef als Templat für das Klasse std::basic_ostream<..>, und die gleiche Situation gilt, wenn die Templat-Funktion operator<< aufrufen.

Überprüfen Sie die Unterschrift des Einfügeoperator ... Ich denke, sie nehmen nicht konstante Ostream Referenz?

Bestätigt mit C ++ 03-Standard, Unterschrift des char * Ausgabeoperator ist:

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);

, die in der Tat eine nicht konstante Referenz nimmt. So Ihr Conversion-Betreiber nicht übereinstimmt.

Wie im Kommentar bemerkt. Das ist irrelevant

Es gibt verschiedene Grenzwerte in der Standard-über Umwandlungen angewendet ... vielleicht dies implizite Konvertierungen benötigen würde (Ihr Operator und Guss auf Basistyp), wenn höchstens sollte man angewendet werden.

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