如何找出输出流链是否结束? [英] how to find out if output stream chain is ended?

查看:136
本文介绍了如何找出输出流链是否结束?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现什么?



如何找到流链是否结束?看看下面的函数(所有这些函数都在这个问题中的一个LogRouter类中):

  template< typename首先,typename。 ..休息> 
void log(const LogLevel& level_,First first_,Rest ... rest_){
sstream< first_<< ;
log(level_,rest _...);
}

void log(const LogLevel& level_){
for(auto& route:routes)
route-> stream()< ; sstream.str()<< std :: endl;

sstream.clear();
sstream.str();
}



我想在上面实现完全相同的功能,但使用流。因此,当我到达一个流的结尾,它需要发送最终数据到路由,而不是使用

 路由器。 log(LogLevel :: Alert,test stream,15); 

我想要能够使用

  router.log(LogLevel :: Alert)< 测试流< 15; 

我尝试过的




  • std :: ostream 操作符重载不接受打包变量。


  • 逐个遍历每个单独传递的值。如下:

      struct LogEnd {}; 

    static LogEnd end(){return LogEnd; }

    template< typename T> LogRouter& operator<<(const T& value){
    sstream<<值;
    return * this;
    }

    LogRouter& log(const LogLevel& level_){
    currentLogLevel = level_; //必须添加另一个变量
    return * this;
    }

    void operator<<(const LogEnd& end){
    for(auto& route:routes)
    route.stream < sstream.str()<< std :: endl;
    currentLogLevel = LogLevel :: None;
    }

    这给了我想要的语法,但我需要调用额外 LogRouter :: end()在每个

      log(LogLevel :: Alert)<< 测试流< 15 << LogRouter :: end(); 

    我有一个语法 std :: endl




问题 / strong>



有没有办法知道流链的结束。

解决方案

您可以将有趣的逻辑放入流的析构函数中。显然,我也会适当地处理流,而不是做一些看起来像流的东西,但不是一个真正的流:

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

class logstream
:private virtual std :: stringbuf
,public std :: ostream {
std :: string level;
public:
logstream(std :: string l)
:std :: ostream(this)
,level(l){
}
(logstream&&& other)
:std :: stringbuf(std :: move(other))
,std :: ostream std :: move(other.level)){
this-> rdbuf(0);
}
〜logstream(){
std :: cout< 在这里做一些有趣的事情(
<< this-> level<<,<< this-> str()<<)\\\

}
};

logstream trace(){
return logstream(trace);
}

int main()
{
trace()< 你好,世界;
}

使用的流缓冲区( std :: stringbuf 在这种情况下,但它也可以是一个自定义流缓冲区)作为一个基类,它在 std :: ostream 之前构建。原则上,它是一个数据成员,但是数据成员是在基类之后构造的。因此,它是一个 private 基类。



原来是 std :: ostream 有一个 virtual 基类( std :: ios std :: ostream 仍然在之前构造std :: stringbuf 如果正常继承用于 std :: stringbuf 。使用 virtual 继承并使 std :: stringbuf 第一个基类确保它首先被构造。 p>

What I am trying to achieve?

How can I find if a stream chain is ended? Look at the function below (all these functions are inside a LogRouter class in this question):

template<typename First, typename... Rest>
void log(const LogLevel &level_, First first_, Rest... rest_) {
    sstream << first_ << " ";
    log(level_, rest_...);
}

void log(const LogLevel &level_) {
    for(auto &route : routes)
        route->stream() << sstream.str() << std::endl;

    sstream.clear();
    sstream.str("");
}

I want to achieve the exact same functionality in the above but using streams. So, when I reach an end of a stream it needs to send the final data to the routes and instead of using

router.log(LogLevel::Alert, "test stream", 15);

I want to be able to use

router.log(LogLevel::Alert) << "test stream " << 15;

What I have tried:

  • std::ostream operator overloading does not accept packed variables.

  • going through every single passed value one by one. Like below:

     struct LogEnd {};
    
     static LogEnd end() { return LogEnd; }
    
     template<typename T> LogRouter &operator<<(const T &value) {
         sstream << value;
         return *this;
     }
    
     LogRouter &log(const LogLevel &level_) {
         currentLogLevel = level_; //had to add another variable
         return *this;
     }
    
     void operator<<(const LogEnd &end) {
        for(auto &route : routes)
            route.stream() << sstream.str() << std::endl;
        currentLogLevel = LogLevel::None;
    }
    

    This gives me what I want syntax wise but I need to call the additional LogRouter::end() at the end of every:

     router.log(LogLevel::Alert) << "test stream " << 15 << LogRouter::end();
    

    I have a syntax for std::endl also but it would be best if I can call it without anything in the end.

Question

Is there a way to know an end of a stream chain. Something similar to what you can do when using recursive variadic template function.

解决方案

You could put the interesting logic into the stream's destructor. Obviously, I would also properly deal with stream rather than cooking up something which somewhat looks like a stream but isn't really a stream:

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

class logstream
    : private virtual std::stringbuf
    , public std::ostream {
    std::string level;
public:
    logstream(std::string l)
        : std::ostream(this)
        , level(l) {
    }
    logstream(logstream&& other)
    : std::stringbuf(std::move(other))
    , std::ostream(std::move(other))
    , level(std::move(other.level)) {
        this->rdbuf(0);
    }
    ~logstream() {
        std::cout << "do something interesting here("
                  << this->level<< ", " << this->str() << ")\n";
    }
};

logstream trace() {
    return logstream("trace");
}

int main()
{
    trace() << "hello, world";
}

The stream buffer used (std::stringbuf in this case but it could also be a custom stream buffer) is made a base class to have it constructed before the std::ostream. In principle it is meant to be a data member but data members are constructed after the base classes. Thus, it is made a private base class instead.

It turns out that std::ostream has a virtual base class (std::ios) which would cause the std::ostream to still be constructed before the std::stringbuf if normal inheritance where used for std::stringbuf. Using virtual inheritance and making the std::stringbuf the first base class makes sure it really is constructed first.

这篇关于如何找出输出流链是否结束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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