我目前有一个日志系统,它接受char *和var args,然后使用它们来执行printf。这适用于C风格的字符串,但我有点清洁。目前,如果我使用std :: stringstream,我必须在日志系统之外创建stringstream,然后将char *用于stringstream给出的字符串。它看起来像这样:
std::stringstream strStream;
strStream << "The value of x is: " << x;
logging::print( strStream.str().c_str() );
我想要的是将参数传递给函数,就像我直接使用字符串流一样。从用户的角度来看,这看起来像这样:
logging::printStream("The value of x is: " << x);
或者可能是这样的:
logging::printStream("The value of x is: ", x);
有没有办法以这样一种方式使用日志记录,即我可以使用字符串流而不必在日志记录系统的函数之外创建它?
这一点尤其重要,因为我打算创建一个宏来阻止任何函数参数在运输版本中进行编译。如果我必须在它之外创建字符串流并将其传入,宏将无用。从技术上讲,我可以创建一个宏来完成我在这个问题中讨论的字符串流的东西,但是这很麻烦,因为我不会总是使用字符串流与此日志记录,所以我将有一个宏用于标准日志记录,并使用不同的宏来使用其中的字符串流调用宏进行标准日志记录。
答案 0 :(得分:1)
以下按预期工作(已测试 - 使用您的logging :: print将输出替换为cerr):
#include<sstream>
#include<iostream>
class StringstreamLogger {
private:
std::stringstream s;
public:
StringstreamLogger () : s (std::ios_base::out) {
}
~StringstreamLogger () {
std::cerr << s.str () << std::endl; // logging::print (s.str ().c_str ());
}
std::stringstream& out () {
return s;
}
};
int main () {
StringstreamLogger ().out () << "My log message";
std::cerr << "Some later output to test for prompt logging (to ensure that logging is not delayed until the end of a block)" << std::endl;
}
答案 1 :(得分:0)
你可以这样写:
print(static_cast<std::ostringstream&>(std::ostringstream() << "The value of x is: " << x).str().c_str());
也许这更符合你的喜好?
答案 2 :(得分:0)
作为起点,你可以......
class Something {
public:
std::ostream& error() const { ... code to return some std::ostream ... }
};
...
int main () {
Something something;
something.error() << "Frobnicate" << 4;
}
稍后您可以使用重载的流操作符添加您自己的代理对象(我认为这比编写从std::ostream
派生的您自己的流更容易。)
当然,那里已经有大量的日志记录框架,首先要查看它们。
答案 3 :(得分:0)
我想出了两个HACK解决方案,但它们应该可以工作。第一个不使用范围解析运算符,更安全。第二个使用noop int变量来伪造范围。
#define logging_printStream(token) { std::stringstream o; o << token; logging::print(o.str().c_str()); }
namespace logging { int noop; }
#define printStream(token) noop = 0; { std::stringstream o; o << token; logging::print(o.str().c_str()); }
int main(int argc, const char** argv)
{
int i = 1;
// MORE SAFE
logging_printStream(i)
logging_printStream("is this magic? " << (i ? "yes" : "no"))
// LESS SAFE
logging::printStream(i)
logging::printStream("is this magic? " << (i ? "yes" : "no"))
}
由于17.6.4.3.2
,我将logging__printStream更新为logging_printStream17.6.4.3.2全局名称[global.names]
某些名称和功能签名集始终保留给实现:
- 包含双下划线_ _ 或以下划线后跟大写字母(2.12)开头的每个名称都保留给实现以供任何使用。
- 以下划线开头的每个名称都保留给实现,以用作全局命名空间中的名称。
由于3.6.1
,我单独留下了main的声明3.6.1主要功能[basic.start.main]
程序应包含一个名为main的全局函数,它是程序的指定开始。实现定义是否需要独立环境中的程序来定义主函数。实现不应预定义主函数。此功能不应过载。 它的返回类型应为int类型,否则其类型为实现定义。
答案 4 :(得分:0)
重载输出流操作符的自定义类型怎么样?
struct logger
{
std::stringstream ss_;
template <typename T>
friend logger& operator << (logger& l, T const& t)
{
#ifdef DEBUG_MODE
l.ss_ << t;
#endif
return l;
}
~logger()
{
#ifdef DEBUG_MODE
// output ss_.str().c_str() to your logger.
#endif
}
};
然后只要你需要记录输出
logger log;
log << "Log this stuff: " << x << '\n';