Question

Je veux utiliser cet extrait de iostreams article de M.-Edd d'imprimer std :: obstrue quelque part.

#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;
}

, dans un mainloop, je vais faire quelque chose comme

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

Voici le ostringstream docs mais je vais avoir du mal à comprendre le meilleur façon de le faire. J'ai une méthode qui affiche le texte, je veux juste l'appeler avec les données contenues dans le ostringstream.

Quel est le plus facile / meilleure façon d'obtenir quoi que ce soit envoyé à std :: saboterie redirigé vers une méthode de mon choix? est comme ci-dessus, et remplir le tout! partie EOF (pas sûr), ou est-il une meilleure façon, dire par une surcharge certains opérateur « commit » quelque part qui appelle ma méthode? Je suis loking pour rapide et facile, je ne veux pas commencer à définir des puits et comme avec iostreams boost que l'article fait -. Ce genre de choses est bien au-dessus de ma tête

Était-ce utile?

La solution

Je vous encourage à regarder Boost.IOStreams . Il semble s'adapter à votre cas d'utilisation bien, et l'utiliser est étonnamment simple:

#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;
}

Autres conseils

penser vous voulez tirer le texte de la ostream alors qu'il est pas vide. Vous pouvez faire quelque chose comme ceci:

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

Faites-moi savoir si ce n'est pas ce que vous vouliez.

Bien sûr, la meilleure solution est d'enlever l'homme du milieu et une nouvelle streambuf aller où vous vraiment veulent, pas besoin de sonder plus tard. quelque chose comme ceci (notez, ce des options de mise en mémoire tampon streambufs et il le fait pour chaque char, mais il y a beaucoup):

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;

}

Je avais besoin de saisir des sorties à std :: et std :: cout cerr des bibliothèques de tiers et de les connecter en utilisant log4cxx, et en conservant les sorties d'origine.

est ce que je suis venu avec. Il est assez straight-forward:

  • Je remplace l'ancien tampon d'un ostream (comme std :: Cout) avec ma propre classe pour que j'avoir accès à ce qui est jamais écrit.

  • Je crée aussi un nouveau objet std :: ostream avec l'ancien tampon afin que je puisse continuer à obtenir la sortie vers la console, en plus de l'envoyer à mon enregistreur. Ce que je trouve genre de pratique.

Code:

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;
};

Ensuite, pour l'utiliser:

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;

Pour l'exemple log4cxx vous devez remplacer le débordement () et de synchronisation () sinon le badbit est toujours réglé après le premier flux est reçu.

Voir: 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;
}

Si vous voulez juste pour obtenir le contenu du ostringstream, utilisez ses membres str (). Par exemple:

string s = oss.str();    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top