c++ - 如何确定输出流链是否结束?

标签 c++ templates c++11 stream

我想达到什么目的?

如何确定流链是否已结束?看看下面的函数(所有这些函数都在这个问题的 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 成为第一个基类可确保它确实首先构造。

关于c++ - 如何确定输出流链是否结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21246317/

相关文章:

c++ - 'N' 的无效模板参数,预期的编译时常量表达式

c++ - 初始化静态成员导致 `Missing type specifier - int assumed.`

c++ - std::regex_search 与 gcc 4.9.1 的结果不一致

c++ - 如何将宏生成的#foo 字符串传递给模板类?

templates - 了解jsf ui的用途 :composition

c++ - 将 std::initializer_list 作为非类型模板参数传递

C++11: string(50, 'x' ) 与 string{50, 'x' }

c++ - argc 和 argv 的目的是什么?

c# - 如何在二进制文件(.net 或非托管)中注入(inject)/更新版本和其他详细信息?

c++11 - 如果两个原子的 fetch_add 同时执行会发生什么?