如何确定输出流链是否结束?
我想要达到什么目的?
如何确定流链是否结束?看看下面的函数(所有这些函数都在这个问题的 LogRouter 类中):
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);
我希望能够使用
router.log(LogLevel::Alert) << "test stream " << 15;
我尝试过的:
std::ostream
运算符重载不接受压缩变量.
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;
}
这给了我我想要的语法明智,但我需要在每个结束时调用额外的 LogRouter::end()
:
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();
我也有 std::endl
的语法,但如果我能在最后不加任何内容的情况下调用它,那将是最好的.
I have a syntax for std::endl
also but it would be best if I can call it without anything in the end.
问题
有没有办法知道流链的末端.类似于使用递归可变参数模板函数时可以执行的操作.
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() << ")
";
}
};
logstream trace() {
return logstream("trace");
}
int main()
{
trace() << "hello, world";
}
使用的流缓冲区(在本例中为std::stringbuf
,但也可以是自定义流缓冲区)被创建为基类,以便在 std::ostream 之前构造它代码>.原则上它是一个数据成员,但数据成员是在基类之后构造的.因此,它变成了一个
private
基类.
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.
事实证明 std::ostream
有一个 virtual
基类 (std::ios
),这会导致 std::ostream
仍然在 std::stringbuf
之前构造,如果用于 std::stringbuf
的正常继承.使用 virtual
继承并使 std::stringbuf
成为第一个基类,确保它确实首先被构造.
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.
相关文章