Domanda

Voglio usare questo frammento di Mr-del Edd iostreams articolo per la stampa di std::zoccolo da qualche parte.

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>

int main()
{
    std::ostringstream oss;

    // Make clog use the buffer from oss
    std::streambuf *former_buff =
        std::clog.rdbuf(oss.rdbuf());

    std::clog << "This will appear in oss!" << std::flush;

    std::cout << oss.str() << '\\n';

    // Give clog back its previous buffer
    std::clog.rdbuf(former_buff);

    return 0;
}

così, in un mainloop, cercherò di fare qualcosa di simile

while (! oss.eof())
{
    //add to window text somewhere
}

Ecco il ostringstream docs ma sto avendo difficoltà a capire il modo migliore per fare questo.Ho un metodo che consente di visualizzare il testo, voglio solo chiamare con tutti i dati in ostringstream.

Che cosa è il modo più semplice/miglior modo per ottenere qualcosa inviati a std::intasare reindirizzato a un metodo di mia scelta?è come sopra, e riempire il tempo !eof parte (non so come), o c'è un modo migliore, diciamo da sovraccarico po 'commit' operatore da qualche parte che chiama il mio metodo?Sto loking per una rapida e facile, io davvero non voglio iniziare a definire lavandini e con una spinta iostreams come l'articolo fa - che roba è il modo sopra la mia testa.

È stato utile?

Soluzione

Vi incoraggio a guardare Boost.IOStreams.Sembra adatta al vostro caso d'uso piacevolmente, e l'utilizzo è estremamente semplice:

#include <boost/iostreams/concepts.hpp> 
#include <boost/iostreams/stream_buffer.hpp>
#include <iostream>

namespace bio = boost::iostreams;

class MySink : public bio::sink
{
public:
    std::streamsize write(const char* s, std::streamsize n)
    {
        //Do whatever you want with s
        //...
        return n;
    }
};

int main()
{
    bio::stream_buffer<MySink> sb;
    sb.open(MySink());
    std::streambuf * oldbuf = std::clog.rdbuf(&sb);
    std::clog << "hello, world" << std::endl;
    std::clog.rdbuf(oldbuf);
    return 0;
}

Altri suggerimenti

Io pensare si desidera estrarre il testo dal ostream mentre non è vuoto.Si potrebbe fare qualcosa di simile a questo:

std::string s = oss.str();
if(!s.empty()) {
    // output s here
    oss.str(""); // set oss to contain the empty string
}

Fatemi sapere se questo non è ciò che si voleva.

Naturalmente, la soluzione migliore è quello di rimuovere il mezzo uomo e hanno un nuovo streambuf andare dove davvero vuoi, non c'è bisogno di sonda in seguito.qualcosa di simile a questo (nota: questo non è per ogni char, ma c'è un sacco di buffering opzioni in streambufs così):

class outbuf : public std::streambuf {
public:
    outbuf() {
        // no buffering, overflow on every char
        setp(0, 0);
    }

    virtual int_type overflow(int_type c = traits_type::eof()) {
        // add the char to wherever you want it, for example:
        // DebugConsole.setText(DebugControl.text() + c);
        return c;
    }
};

int main() {
    // set std::cout to use my custom streambuf
    outbuf ob;
    std::streambuf *sb = std::cout.rdbuf(&ob);

    // do some work here

    // make sure to restore the original so we don't get a crash on close!
    std::cout.rdbuf(sb);
    return 0;

}

Avevo bisogno di afferrare le uscite di std::cout e std::cerr da librerie di terze parti e accedere utilizzando log4cxx, e ancora conserva l'originale uscite.

Questo è quello che mi è venuto con.È abbastanza straight-forward:

  • Sostituire il vecchio buffer di una ostream (come std::cout) con la mia classe in modo che posso accedere a qualsiasi cosa venga scritta su di esso.

  • Ho anche creare un nuovo std::ostream oggetto con il vecchio buffer in modo che io possa continuare ad ottenere in uscita per la console, oltre all'invio al mio strumento.Che tipo di utile.

Codice:

class intercept_stream : public std::streambuf{
public:
    intercept_stream(std::ostream& stream, char const* logger):
      _logger(log4cxx::Logger::getLogger(logger)),
      _orgstream(stream),
      _newstream(NULL)
    {
        //Swap the the old buffer in ostream with this buffer.
        _orgbuf=_orgstream.rdbuf(this);
        //Create a new ostream that we set the old buffer in
        boost::scoped_ptr<std::ostream> os(new std::ostream(_orgbuf));
        _newstream.swap(os);
    }
    ~intercept_stream(){
        _orgstream.rdbuf(_orgbuf);//Restore old buffer
    }
protected:
    virtual streamsize xsputn(const char *msg, streamsize count){
        //Output to new stream with old buffer (to e.g. screen [std::cout])
        _newstream->write(msg, count);
        //Output to log4cxx logger
        std::string s(msg,count);
        if (_logger->isInfoEnabled()) {
            _logger->forcedLog(::log4cxx::Level::getInfo(), s, LOG4CXX_LOCATION); 
        }
        return count;
    }
private:
    log4cxx::LoggerPtr _logger;
    std::streambuf*    _orgbuf;
    std::ostream&      _orgstream;
    boost::scoped_ptr<std::ostream>  _newstream;
};

Quindi per utilizzarla:

std::cout << "This will just go to my console"<<std::endl;
intercept_stream* intercepter = new intercept_stream(std::cout, "cout");
std::cout << "This will end up in both console and my log4cxx logfile, yay!" << std::endl;

Per il log4cxx esempio, è necessario eseguire l'override di overflow() e sync ()), altrimenti la badbit è sempre impostato dopo il primo flusso è ricevuto.

Vedere:http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/fd9d973282e0a402/a872eaedb142debc

InterceptStream::int_type InterceptStream::overflow(int_type c)
{
    if(!traits_type::eq_int_type(c, traits_type::eof()))
    {
        char_type const t = traits_type::to_char_type(c);
        this->xsputn(&t, 1);
    }
    return !traits_type::eof();
}

int InterceptStream::sync()
{
    return 0;
}

Se si desidera solo per ottenere il contenuto del ostringstream, quindi utilizzare le sue str() membro.Per esempio:

string s = oss.str();    
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top