我想要实现的目标是什么?
如何查找流链是否已结束?看看下面的函数(在这个问题中所有这些函数都在一个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
的语法,但最好是在最后没有任何内容的情况下调用它。
问题
有没有办法知道流链的结束。类似于使用递归可变参数模板函数时可以执行的操作。
答案 0 :(得分: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";
}
使用的流缓冲区(在这种情况下为std::stringbuf
,但它也可以是自定义流缓冲区)成为基类,以便在std::ostream
之前构建它。原则上它意味着是数据成员,但数据成员是在基类之后构造的。因此,它改为private
基类。
事实证明std::ostream
有一个virtual
基类(std::ios
)会导致std::ostream
仍然在std::stringbuf
之前构建,如果正常的话用于std::stringbuf
的继承。使用virtual
继承并使std::stringbuf
成为第一个基类,确保它首先被构造。