c ++在任何时候写入流时执行函数 [英] c++ execute function any time a stream is written to

查看:207
本文介绍了c ++在任何时候写入流时执行函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的GUI程序,使用自定义 stringstream 将输出从控制台重定向到GUI中的文本字段(在某些情况下)。目前。窗口在任何时候重新绘制,我输入,但有可能输出可以在其他时间生成。是否有一种方法使用 stringstream 注册一个函数,每次使用<



我应该指出,我不能在我的解决方案中使用C ++ 11。

解决方案

个人而言,我不会使用 std :: ostringstream (甚至 std :: stringstream )!相反,我将创建自己的流缓冲区,以便将数据发送到GUI。也就是说,我将覆盖 std :: streambuf :: overflow() std :: streambuf :: sync()将当前数据发送到GUI。为了确保任何输出立即被发送,我会建立一个 std :: ostream std :: ios_base :: unitbuf 设置。实际上,发送对函数的更改是很简单的,即,我将实现这个:

  #include< streambuf> 
#include< ostream>
#include< functional>
#include< string>
#include< memory>
#include< iostream> //仅用于测试...

#if HAS_FUNCTION
typedef std :: function< void(std :: string)> function_type;
#else
class function_type
{
private:
struct base {
virtual〜base(){}
virtual base * clone )const = 0;
virtual void call(std :: string const&)= 0;
};
template< typename Function>
struct concrete
:base {
函数d_function;
具体(函数功能)
:d_function(函数){
}
base * clone()const {return new concrete< Function>(this-> d_function); }
void call(std :: string const& value){this-> d_function(value); }
};
std :: auto_ptr< base> d_function;
public:
template< typename Function>
function_type(function function)
:d_function(new concrete< Function>(function)){
}
function_type(function_type const& other)
:d_function .d_function-> clone()){
}
function_type& operator =(function_type other){
this-> swap(other);
return * this;
}
〜function_type(){}
void swap(function_type& other){
std :: swap(this-> d_function,other.d_function);
}
void operator()(std :: string const& value){
this-> d_function-> call(value);
}
};
#endif

class functionbuf
:public std :: streambuf {
private:
typedef std :: streambuf :: traits_type traits_type;
function_type d_function;
char d_buffer [1024];
int overflow(int c){
if(!traits_type :: eq_int_type(c,traits_type :: eof())){
* this-> pptr()= traits_type :: to_char_type(c);
this-> pbump(1);
}
return this-> sync()? traits_type :: not_eof(c):traits_type :: eof();
}
int sync(){
if(this-> pbase()!= this-> pptr()){
this-> d_function(std: :string(this-> pbase(),this-> pptr()));
this-> setp(this-> pbase(),this-> epptr());
}
return 0;
}
public:
functionbuf(function_type const& function)
:d_function(function){
this-> setp(this-> d_buffer, > d_buffer + sizeof(this-> d_buffer)-1);
}
};

class ofunctionstream
:private virtual functionbuf
,public std :: ostream {
public:
offunctionstream(function_type const& function)
:functionbuf(function)
,std :: ostream(static_cast< std :: streambuf *>(this)){
this-> flags(std :: ios_base :: unitbuf);
}
};

void some_function(std :: string const& value){
std :: cout< some_function(<< value<<)\\\
;
}

int main(){
ofunctionstream out(& some_function);
out<< hello< ','< world:< 42 << \\\
;
out<< std :: nounitbuf< not< as<< 许多< calls\\\
< std :: flush;
}

上面代码的一大块实际上与手头的任务无关:它实现 std :: function< void(std :: string)> 的原始版本,以防C ++ 2011不能使用。



如果你不想调用的话,你可以关闭 std :: ios_base :: unitbuf 在冲洗流时,使用 std :: flush (是的,我知道 std :: endl 但不幸的是,推荐摆脱它,并使用 std :: flush 在其中flush是真正的意思)。


I have a simple GUI program that uses a custom stringstream to redirect output from the console to a text field in the GUI (under some circumstances). currently. the window redraws any time I hit enter, but it's possible that output could be generated at other times. Is there a way to register a function with the stringstream that gets executed every time the << operator is used on the stream?

NOTE

I should have pointed out that I cannot use C++11 in my solution. the machines on which this will be compiled and run will not have c++11 available.

解决方案

Personally, I wouldn't use an std::ostringstream (or even an std::stringstream) for this at all! Instead, I would create my own stream buffer taking care of sending the data to the GUI. That is, I'd overwrite std::streambuf::overflow() and std::streambuf::sync() to send the current data to the GUI. To also make sure that any output is sent immediately, I'd set up an std::ostream to have std::ios_base::unitbuf set. Actually, sending the changes to a function is quite simple, i.e., I'll implement this:

#include <streambuf>
#include <ostream>
#include <functional>
#include <string>
#include <memory>
#include <iostream> // only for testing...

#if HAS_FUNCTION
typedef std::function<void(std::string)> function_type;
#else
class function_type
{
private:
    struct base {
        virtual ~base() {}
        virtual base* clone() const = 0;
        virtual void  call(std::string const&) = 0;
    };
    template <typename Function>
    struct concrete
        : base {
        Function d_function;
        concrete(Function function)
            : d_function(function) {
        }
        base* clone() const { return new concrete<Function>(this->d_function); }
        void  call(std::string const& value) { this->d_function(value); }
    };
    std::auto_ptr<base> d_function;
public:
    template <typename Function>
    function_type(Function function)
        : d_function(new concrete<Function>(function)) {
    }
    function_type(function_type const& other)
        : d_function(other.d_function->clone()) {
    }
    function_type& operator= (function_type other) {
        this->swap(other);
        return *this;
    }
    ~function_type() {}
    void swap(function_type& other) {
        std::swap(this->d_function, other.d_function);
    }
    void operator()(std::string const& value) {
        this->d_function->call(value);
    }
};
#endif

class functionbuf
    : public std::streambuf {
private:
    typedef std::streambuf::traits_type traits_type;
    function_type d_function;
    char          d_buffer[1024];
    int overflow(int c) {
        if (!traits_type::eq_int_type(c, traits_type::eof())) {
            *this->pptr() = traits_type::to_char_type(c);
            this->pbump(1);
        }
        return this->sync()? traits_type::not_eof(c): traits_type::eof();
    }
    int sync() {
        if (this->pbase() != this->pptr()) {
            this->d_function(std::string(this->pbase(), this->pptr()));
            this->setp(this->pbase(), this->epptr());
        }
        return 0;
    }
public:
    functionbuf(function_type const& function)
        : d_function(function) {
        this->setp(this->d_buffer, this->d_buffer + sizeof(this->d_buffer) - 1);
    }
};

class ofunctionstream
    : private virtual functionbuf
    , public std::ostream {
public:
    ofunctionstream(function_type const& function)
        : functionbuf(function)
        , std::ostream(static_cast<std::streambuf*>(this)) {
        this->flags(std::ios_base::unitbuf);
    }
};

void some_function(std::string const& value) {
    std::cout << "some_function(" << value << ")\n";
}

int main() {
    ofunctionstream out(&some_function);
    out << "hello" << ',' << " world: " << 42 << "\n";
    out << std::nounitbuf << "not" << " as " << "many" << " calls\n" << std::flush;
}

A fair chunk of the above code is actually unrelated to the task at hand: it implements a primitive version of std::function<void(std::string)> in case C++2011 can't be used.

If you don't want quite as many calls, you can turn off std::ios_base::unitbuf and only sent the data upon flushing the stream, e.g. using std::flush (yes, I know about std::endl but it unfortunately is typically misused to I strongly recommend to get rid of it and use std::flush where a flush is really meant).

这篇关于c ++在任何时候写入流时执行函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆