std::endl



  • so ginge es auch(dann kannste auch mehr ausgeben, als einzelne zeichen :D)

    class Log
    {
      ostream os;
      public:
        template<class T>
        Log& operator << (const T& c)
        {
          os << c;
          return *this;
        }
    
      // anderer Krempel..
    };
    


  • streambuf bauen



  • Orillion schrieb:

    class Log
    {
      ostream os;
      public:
        Log& operator << (char c)
        {
          os << c;
          return *this;
        }
    
      // anderer Krempel..
    };
    

    Wie kann ich in meine Klasse so schreiben, dass sie auch std::endl akzeptiert?

    std::endl ist eine Funktion; bzw. genauer eine Template-Funktion. Die Signatur ist

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

    Wenn die Ausgabe immer auf einen std::ostream gehen soll, so genügt es einen operator für Funktionen hinzuzufügen:

    class Log
    {
    public:
        typedef std::ostream& (*manip_type)( std::ostream& );
        Log& operator<<( manip_type manip )
        {
            os << manip;
            return *this;
        }
        // anderer Krempel..
    };
    

    Gruß
    Werner



  • @Werner: Das klingt nicht sonderlich brauchbar und ist imho nciht im Sinne des Erfinders.

    MfG SideWinder



  • SideWinder schrieb:

    @Werner: Das klingt nicht sonderlich brauchbar und ist imho nciht im Sinne des Erfinders.

    Könntest du das mal bitte begründen. Ich mache das bisher auch immer so und bin damit bisher gut gefahren. Vorallem, da

    template<class T>
        Log& operator << (const T& c)
        {
          os << c;
          return *this;
        }
    

    in diesem Fall nicht funktioniert, da T hier schlicht mehrdeutig ist.



  • HumeSikkins schrieb:

    SideWinder schrieb:

    @Werner: Das klingt nicht sonderlich brauchbar und ist imho nciht im Sinne des Erfinders.

    Könntest du das mal bitte begründen. Ich mache das bisher auch immer so und bin damit bisher gut gefahren. Vorallem, da ... in diesem Fall nicht funktioniert, da T hier schlicht mehrdeutig ist.

    Also das mit der Mehrdeutigkeit von dem Template-T gehört wohl mit zum System und ich weiß nicht, wieso es nicht funktionieren sollte.

    Wenn man für Manipulator-Funktionen überlädt, sollte man auch für den ganzen anderen Krams überladen (also ostream, string etc.). Letztlich halte ich

    rrrrrrrrrrrrr schrieb:

    streambuf bauen

    für das Sinnvollste. Der Log-Stream ist schließlich auch nur ein Ausgabestream (zur Not halt ableiten, falls man irgendwelchen Zusatzkrams (Zeit o.ä.) brauch).



  • .filmor schrieb:

    Also das mit der Mehrdeutigkeit von dem Template-T gehört wohl mit zum System und ich weiß nicht, wieso es nicht funktionieren sollte.

    Wie bereits gesagt wurde hat endl (und die anderen Manipulatoren ohne Parameter) den Typ:

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

    Es handelt sich also um ein *Template*. Ein Template passt nun aber nicht auf ein anderes Template. Es fehlen ja dabei die konkreten Typen mit denen man das Template instanziieren könnte. Und aus den Fingern saugt sich der Compiler keine Typen. Deshalb muss man den op<< für ein (oder mehrere) *konkrete* Manipulator-Typen überladen. Normalerweise reichen zwei (einmal für ostream und einmal für wostream).

    .filmor schrieb:

    Wenn man für Manipulator-Funktionen überlädt, sollte man auch für den ganzen anderen Krams überladen (also ostream, string etc.).

    Verstehe nicht was du meinst. Es reicht doch ein operator<<-Template für die "normalen" Typen und ein bis zwei Überladungen für Manipulatoren.
    Was meinst du jetzt mit "anderen Krams"?

    Letztlich halte ich

    rrrrrrrrrrrrr schrieb:

    streambuf bauen

    für das Sinnvollste.

    Prinzipiell eine gute Sache. Ist aber blöd, wenn man den LogStream auch zu einem Null-Overhead-NullStream machen möchte (d.h. z.B. im Release-Modus kein Logging). Das geht mit einem Streambuffer nicht, da die Formatierung vorher schon im Stream durchgeführt wurde.
    Hierfür habe ich z.B. ganz gerne den oben genannten Ansatz benutzt.



  • Verstehe. Aber

    log << std::endl<char, std::char_traits<char> >;
    

    klappt 😉

    Bzgl. Null-Overhead Nullstream: Macht man Debugging-Ausgaben im Normalfall nicht sowieso mit Makros, die bei NDEBUG rausfliegen, so wie asserts?

    Wenn man Streams benutzen will, dann muss Log doch eigentlich auch ein ostream sein, sonst klappt z.B. das Aneinanderreihen nicht, ohne welches man auf den <<-Operator verzichten und das Logging mit einem Log-Streambuffer und einem Debug-Makro machen könnte.



  • .filmor schrieb:

    HumeSikkins schrieb:

    SideWinder schrieb:

    @Werner: Das klingt nicht sonderlich brauchbar und ist imho nciht im Sinne des Erfinders.

    Könntest du das mal bitte begründen. Ich mache das bisher auch immer so und bin damit bisher gut gefahren. Vorallem, da ... in diesem Fall nicht funktioniert, da T hier schlicht mehrdeutig ist.

    Also das mit der Mehrdeutigkeit von dem Template-T gehört wohl mit zum System und ich weiß nicht, wieso es nicht funktionieren sollte.

    Hallo Filmor,

    das ist interessant! Bei mir funktioniert

    template<class T>
        Log& operator << (const T& c)
    

    in keinem Fall mit 'std::endl'. Egal welchen Compiler ich benutze (VC6, 7, 8, Comeau). Und warum ist das Überladen mit dem Manipulator nicht 'im Sinne des Erfinders'?

    .filmor schrieb:

    Wenn man für Manipulator-Funktionen überlädt, sollte man auch für den ganzen anderen Krams überladen (also ostream, string etc.). Letztlich halte ich

    rrrrrrrrrrrrr schrieb:

    streambuf bauen

    für das Sinnvollste. Der Log-Stream ist schließlich auch nur ein Ausgabestream (zur Not halt ableiten, falls man irgendwelchen Zusatzkrams (Zeit o.ä.) brauch).

    Ich verstehe hier überhaupt nicht, wie ein selbstgebauter Streambuf hier weiterhelfen soll. Kannst Du das bitte erläutern. 😕

    Gruß
    Werner



  • Reicht es, wenn ich auf das verweise, was ich fast 4 Stunden vor deinem Beitrag geschrieben hab?



  • .filmor schrieb:

    Reicht es, wenn ich auf das verweise, was ich fast 4 Stunden vor deinem Beitrag geschrieben hab?

    Hallo Filmor,

    um ehrlich zu sein; ich steh' etwa auf dem Schlauch 😕 . Du meinst wahrscheinlich Deinen Beitrag von 16:18:30 31.10.2005. Nun das compiliert zwar unter Comeau, aber für den VC8 ist es immer noch mehrdeutig. Darüber hinaus wäre es für mich auch keine Lösung statt 'endl' jedesmal 'std::endl<char, std::char_traits<char> >' zu schreiben.
    Ich würde auf jeden Fall meinen Vorschlag mit den operator für Manipulatoren bevorzugen.

    Und warum auch nicht - und das ist das nächste was ich nicht verstehe - Du schriebst

    .filmor schrieb:

    Wenn man für Manipulator-Funktionen überlädt, sollte man auch für den ganzen anderen Krams überladen (also ostream, string etc.).

    Warum sollte man dies tun, wenn die Template-Lösung dies alles erschägt?

    Weiter schreibst Du

    .filmor schrieb:

    Letztlich halte ich

    rrrrrrrrrrrrr schrieb:

    streambuf bauen

    für das Sinnvollste. Der Log-Stream ist schließlich auch nur ein Ausgabestream (zur Not halt ableiten, falls man irgendwelchen Zusatzkrams (Zeit o.ä.) brauch).

    Die Frage ist letzlich, was der OP mit der Klasse Log letztlich bezwecken will. Ich kenne solche Konstruktionen, wenn man z.B. in Multi-Thread-Umgebungen ein Mutex locken möchte, welches die Ausgabe verschiedener Threads gegeneinander verriegelt, oder wenn vor jeder Ausgabe z.B. ein Timestamp mit rauskommen soll.
    Das oder ähnliches könnte eine Log-Klasse erledigen. Aber ein Streambuf ist dafür in keinen Fall die richtige Baustelle.

    Gruß
    Werner



  • Nun denn, zuerst einmal war das mit

    log << std::endl<char, std::char_traits<char> >;
    

    nicht ernst gemeint, daher der (eigentlich doch sehr geläufige) zwinkernde Smiley dahinter. Natürlich ist das nicht praktikabel.

    Desweiteren meinte ich, dass man für eine echte Streamfunktionalität (und nur das macht es sinnvoll den Shiftoperator zu nutzen) einen ganzen Haufen an Operatoren überladen muss und dies daher imho genauso unpraktikabel ist wie das oben genannte Beispiel. Deshalb teile ich r13's Meinung, einen echten ostream zu nehmen und diesem einen gescheiten Logging-Streambuffer zu bauen.

    Bezüglich des Overheads meinte ich dann, dass man diesen sowieso nur mit Debugging-Makros verhindern könnte und für diese die Streamsyntax nicht benutzbar ist.

    Ich hoffe, ich konnte dich über meine Ansichten erleuchten.



  • .filmor schrieb:

    Ich hoffe, ich konnte dich über meine Ansichten erleuchten.

    Ja konntest Du. Dank' Dir Filmor.

    Gruß
    Werner


Anmelden zum Antworten