Frage

Ich versuche, meine eigene Logging-Klasse zu schreiben und verwenden Sie es als ein Strom:

logger L;
L << "whatever" << std::endl;

Dies ist der Code, den ich mit gestartet:

#include <iostream>

using namespace std;


class logger{
public:
    template <typename T>
    friend logger& operator <<(logger& log, const T& value);
};

template <typename T>
logger& operator <<(logger& log, T const & value) {
    // Here I'd output the values to a file and stdout, etc.
    cout << value;
    return log;
}

int main(int argc, char *argv[])
{
    logger L;
    L << "hello" << '\n' ; // This works
    L << "bye" << "alo" << endl; // This doesn't work
    return 0;
}

Aber ich war ein Fehler, wenn ich versuche zu sagen zu kompilieren, dass es keine Definition für Betreiber war << (wenn std :: endl):

pruebaLog.cpp:31: error: no match for ‘operator<<’ in ‘operator<< [with T = char [4]](((logger&)((logger*)operator<< [with T = char [4]](((logger&)(& L)), ((const char (&)[4])"bye")))), ((const char (&)[4])"alo")) << std::endl’

Also, ich habe Überlastung Operator versucht << diese Art von Strömen zu akzeptieren, aber es macht mich verrückt. Ich weiß nicht, wie es zu tun. Ich habe bei worden Loking zum Beispiel der Definition von std :: endl am Ostream Header-Datei und eine Funktion mit diesem Header geschrieben:

logger& operator <<(logger& log, const basic_ostream<char,char_traits<char> >& (*s)(basic_ostream<char,char_traits<char> >&))

Aber kein Glück. Ich habe die gleichen Vorlagen versucht, mit, anstatt direkt mit Saibling, und auch einfach versucht „const ostream & o“ und nichts mit.

Eine andere Sache, nervt mich das heißt, in der Fehlerausgabe, das erste Argument für Operator << Änderungen, manchmal ist es ein Verweis auf einen Zeiger, sieht manchmal wie eine doppelte Referenz ...

War es hilfreich?

Lösung

endl ist ein seltsames Tier. Es ist kein konstanter Wert. Es ist eigentlich, alle Dinge, eine Funktion. Sie benötigen eine spezielle Überschreibung die Anwendung von endl zu behandeln:

logger& operator<< (logger& log, ostream& (*pf) (ostream&))
{
  cout << pf;
  return log;
}

Dies nimmt Einfügung einer Funktion, die eine Referenz ostream und gibt eine Referenz nimmt ostream. Das ist, was endl ist.

Edit: Als Reaktion auf FranticPedantic die interessante Frage nach dem "Warum kann nicht der Compiler deduce dies automatisch?". Der Grund dafür ist, dass wenn man noch tiefer tauchen, endl ist eigentlich selbst eine template Funktion. Es ist wie folgt definiert:

template <class charT, class traits>
  basic_ostream<charT,traits>& endl ( basic_ostream<charT,traits>& os );

Das heißt, es kann jede Art von ostream als Eingang und Ausgang nehmen. So ist das Problem nicht, dass der Compiler ist nicht, dass T const & ableiten könnte ein Funktionszeiger sein, aber dass es nicht herausfinden kann, die endl Sie passieren sollten. Die Templat-Version operator<< vorgestellt in der Frage würde einen Zeiger auf jede Funktion als zweites Argument, aber zugleich die endl Vorlage stellt eine unendlich Menge potentieller Funktionen übernehmen, so dass der Compiler nicht alles tun kann sinnvoll da.

Die Bereitstellung der besondere Überlastung der operator<< deren zweite Argument entspricht eine spezifische Instanziierung der endl Vorlage kann den Anruf zu lösen.

Andere Tipps

endl ist ein IO-Manipulator, der ein Funktors ist, die einen Strom durch Verweis akzeptiert, führt eine Operation auf, und kehrt, dass Strom, der auch durch Bezugnahme eingeschlossen. cout << endl entspricht cout << '\n' << flush, wo flush ist ein Manipulator, der den Ausgangspuffer leert.

In Ihrer Klasse, brauchen Sie nur eine Überlastung für diesen Operator zu schreiben:

logger& operator<<(logger&(*function)(logger&)) {
    return function(*this);
}

Wo logger&(*)(logger&) der Typ einer Funktion zu akzeptieren und eine logger durch Verweis zurück. Um Ihre eigenen Manipulatoren zu schreiben, schreiben Sie einfach eine Funktion, die Streichhölzer, dass die Unterzeichnung und haben sie eine Operation auf dem Strom durchführen:

logger& newline(logger& L) {
    return L << '\n';
}

Ich glaube, dass das Problem ist Ihr Strom nicht operator<< nicht überlastet, eine Funktion zu übernehmen, die den gleichen Typ wie std::endl hat, wie in dieser Antwort dargestellt: std :: endl aus unbekannter Art, wenn Betreiber Überlastung <<

In C ++ ist der Strompuffer , die den Basiswert I / O mechanisim kapselt. Der Strom selbst kapselt nur die Conversions zu bespannen, und die E / A-Richtung.

So sollten Sie eine der vordefinierten Stream-Klassen verwenden, anstatt Ihre eigenen. Wenn Sie ein neues Ziel haben Sie Ihre E / A gehen wollen, um (wie eine System-Log), was sollten Sie erschaffen Ihre eigenen Strompuffer (von std::streambuf abgeleitet).

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