سؤال

أريد استخدام هذا المقتطف من مقال السيد إد iostreams لطباعة std::clog في مكان ما.

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

لذا، في الحلقة الرئيسية، سأفعل شيئًا مثل

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

هنا مستندات ostringstream لكني أجد صعوبة في فهم أفضل طريقة للقيام بذلك.لدي طريقة تعرض النص، أريد فقط استدعائها مع أي بيانات في ostringstream.

ما هي الطريقة الأسهل/الأفضل لإعادة توجيه أي شيء مرسل إلى std::clog إلى طريقة من اختياري؟هل هو كما هو مذكور أعلاه، واملأ الجزء while !eof (لست متأكدًا من كيفية ذلك)، أم أن هناك طريقة أفضل، على سبيل المثال عن طريق التحميل الزائد لبعض مشغلي "الالتزام" في مكان ما يستدعي طريقتي؟أنا أبحث عن طريقة سريعة وسهلة، ولا أريد حقًا أن أبدأ في تحديد المصارف وما شابه ذلك من خلال تدفقات iostream المعززة كما تفعل المقالة - فهذه الأشياء فوق رأسي.

هل كانت مفيدة؟

المحلول

أنا أشجعك على النظر Boost.IOStreams.يبدو أنه يناسب حالة الاستخدام الخاصة بك بشكل جيد، واستخدامه بسيط بشكل مدهش:

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

نصائح أخرى

أنا يفكر تريد سحب النص من ostream وهو ليس فارغًا.يمكنك أن تفعل شيئا مثل هذا:

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

اسمحوا لي أن أعرف إذا لم يكن هذا هو ما أردت.

بالطبع، الحل الأفضل هو إزالة الوسيط والحصول على تيار جديد أينما كنت حقًا تريد ذلك، لا حاجة للتحقيق في وقت لاحق.شيء من هذا القبيل (لاحظ أن هذا يتم مع كل حرف، ولكن هناك الكثير من خيارات التخزين المؤقت في Streambufs أيضًا):

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;

}

كنت بحاجة للحصول على مخرجات std::cout وstd::cerr من مكتبات الطرف الثالث وتسجيلها باستخدام log4cxx، مع الاحتفاظ بالمخرجات الأصلية.

هذا هو ما خطرت لي.إنها جميلة ومباشرة:

  • أقوم باستبدال المخزن المؤقت القديم لـ ostream (مثل std::cout) بفصلي الخاص حتى أتمكن من الوصول إلى ما هو مكتوب عليه.

  • أقوم أيضًا بإنشاء كائن std::ostream جديد باستخدام المخزن المؤقت القديم حتى أتمكن من الاستمرار في الحصول على الإخراج إلى وحدة التحكم الخاصة بي، بالإضافة إلى إرساله إلى المسجل الخاص بي.الذي أجده مفيدًا نوعًا ما.

شفرة:

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

ثم لاستخدامه:

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;

لالمثال log4cxx يجب تجاوز تجاوز () والمزامنة () وإلا يتم تعيين badbit دائما بعد استلام الرافد الأول.

وانظر: 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;
}

إذا كنت ترغب فقط في الحصول على محتويات ostringstream، ثم استخدم الأعضاء فيها شارع (). على سبيل المثال:

string s = oss.str();    
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top