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

Gas*_*sim 2 c++ templates stream c++11

我想要实现的目标是什么?

如何查找流链是否已结束?看看下面的函数(所有这些函数都在这个问题的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("");
}
Run Code Online (Sandbox Code Playgroud)

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

router.log(LogLevel::Alert, "test stream", 15);
Run Code Online (Sandbox Code Playgroud)

我希望能够使用

router.log(LogLevel::Alert) << "test stream " << 15;
Run Code Online (Sandbox Code Playgroud)

我尝试过的:

  • 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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这给了我想要的语法,但我需要LogRouter::end()在每个结尾处调用附加内容:

     router.log(LogLevel::Alert) << "test stream " << 15 << LogRouter::end();
    
    Run Code Online (Sandbox Code Playgroud)

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

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

Die*_*ühl 6

您可以将有趣的逻辑放入流的析构函数中.显然,我也会妥善处理流而不是烹饪一些看起来像流的东西,但实际上不是流:

#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";
}
Run Code Online (Sandbox Code Playgroud)

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

事实证明,它std::ostream有一个virtual基类(std::ios),它会导致std::ostream仍然在std::stringbufif正常继承之前构造std::stringbuf.使用virtual继承并创建第std::stringbuf一个基类可确保它首先构建.