如何确定输出流链是否已结束?

how to find out if output stream chain is ended?

本文关键字:结束 是否 何确定 输出流      更新时间:2023-10-16

我想实现什么?

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

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("");
}

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

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

我希望能够使用

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

我尝试过的:

  • std::ostream运算符重载不接受打包变量。

  • 逐个检查每个传递的值。如下所示:

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

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

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

    我也有一个std::endl语法,但最好是我可以在最后没有任何内容的情况下调用它。

问题

有没有办法知道流链的末端。类似于使用递归可变参数模板函数时可以执行的操作。

您可以将有趣的逻辑放入流的析构函数中。显然,我也会正确处理流,而不是制作一些看起来有点像溪流但实际上不是流的东西:

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

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

事实证明,std::ostream有一个virtual基类(std::ios),如果用于std::stringbuf的正常继承,这将导致std::ostream仍然在std::stringbuf之前构造。使用virtual继承并将std::stringbuf作为第一个基类可确保它确实首先构造。