my_macro << 1 << "hello world" << blah->getValue() << std::endl;
应扩展为:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
my_macro << 1 << "hello world" << blah->getValue() << std::endl;
应扩展为:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
#define my_macro my_stream()
class my_stream: public std::ostringstream {
public:
my_stream() {}
~my_stream() {
ThreadSafeLogging(this->str());
}
};
int main() {
my_macro << 1 << "hello world" << std::endl;
}
创建了一个临时类型my_stream
,它是ostringstream
. 对该临时文件的所有操作都像在ostringstream
.
当语句结束时(即在 main() 中整个打印操作的分号之后),临时对象超出范围并被销毁。my_stream
析构函数调用ThreadSafeLogging
之前“收集”的数据。
经过测试(g++)。
感谢/感谢dingo指出如何简化整个事情,所以我不需要重载的operator<<
. 可惜点赞不能分享。
难道你不能从 ostream 派生并提供你自己的线程安全实现吗?然后你可以做
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
并在没有宏的情况下获得完全相同的功能并正确使用 C++?
不可以。问题在于,如果不使用函数语法,宏仅限于被替换它所在的位置。
但是,如果您愿意使用函数语法,则可以在 args 之前和之后替换东西。
my_macro(1 << "hello world" << blah->getValue() << std::endl);
您可以通过将 MyMacro 定义为:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
考虑到您的代码中包含这些行,是的,有可能
#include <iostream>
#include <sstream>
__LINE__
宏由所有标准编译器定义。所以我们可以用它来生成一个变量名,每次你使用宏时都是不同的:)
这是一个仅被视为单语句指令的新版本:(已编辑)
#define Var_(Name, Index) Name##Index
#define Var(Name, Index) Var_(Name, Index)
#define my_macro \
for (struct { int x; std::ostringstream oss; } Var(s, __LINE__) = { 0 }; \
Var(s, __LINE__).x<2; ++Var(s, __LINE__).x) \
if (Var(s, __LINE__).x==1) ThreadSafeLogging(Var(s, __LINE__).oss.str()); \
else Var(s, __LINE__).oss
// So you can use it like this
int main()
{
if (4 != 2)
my_macro << 4 << " hello " << std::endl;
my_macro << 2 << " world !" << std::endl;
}
由于 operator 的简单性,Developper 可能不需要在同一行上使用此宏两次<<
。但是如果你需要这个,你可以切换使用__LINE__
by __COUNTER__
(这是非标准的!)。感谢 Quuxplusone 的提示
这是我在其他地方看到的另一个讨厌的把戏。与我的其他答案相比,它有一个明显的缺点:您不能在同一范围内使用它两次,因为它声明了一个变量。但是,对于somemacro foo
您希望在 foo
.
#define my_macro \
std::ostringstream oss; \
for (int x=0; x<2; ++x) \
if (x==1) ThreadSafeLogging(oss.str()); \
else oss
int main() {
my_macro << 1 << "hello world" << std::endl;
}
我的日志记录设置非常相似:
bool ShouldLog(const char* file, size_t line, Priority prio);
class LoggerOutput : public std::stringstream {
public:
LoggerOutput(const char* file, size_t line, Priority prio)
: prio(prio)
{
Prefix(file, line, prio);
}
void Prefix(const char* file, size_t line, Priority prio);
~LoggerOutput() {
Flush();
}
void Flush();
private:
Priority prio;
};
#define LOG(Prio) if (!Logging::ShouldLog(__FILE__, __LINE__, Prio)) {} else Logging::LoggerOutput(__FILE__, __LINE__, Prio)
如果您的日志记录被禁用,则永远不会创建 ostream,并且几乎没有开销。您可以配置文件名和行号或优先级的日志记录。ShouldLog 函数可以在调用之间更改,因此您可以限制或限制输出。日志输出使用两个函数来修改自身,Prefix 将“file:line: (PRIO)”前缀添加到该行,Flush() 将其作为单个命令刷新到日志输出并添加换行符. 在我的实现中它总是这样,但如果还没有的话,你可以让它有条件。