my_macro << 1 << "hello world" << blah->getValue() << std::endl;
应扩展为:
std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
答案 0 :(得分:72)
#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 ++)。
感谢{/ 3}}指出如何简化整个事情,所以我不需要重载operator<<
。太糟糕的upvotes无法分享。
答案 1 :(得分:3)
难道你不能从ostream派生并提供自己的线程安全实现吗?然后你可以做
myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;
在没有宏的情况下获得完全相同的功能并正确使用C ++?
答案 2 :(得分:2)
没有。问题是如果不使用函数语法,宏只限于被替换的地方。
但是如果你愿意使用函数语法,那么你可以在args之前和之后替换东西。
my_macro(1 << "hello world" << blah->getValue() << std::endl);
您可以将MyMacro定义为:
#define my_macro(args) std::ostreamstring oss; \
oss << args; \
ThreadSafeLogging(oss.str());
答案 3 :(得分:2)
答案 4 :(得分:2)
考虑到你的代码中包含了这些行,是的,这是可能的
#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;
}
由于操作符<<
的简单性,开发者可能不需要在同一行上使用此宏两次。但是如果你需要这个,你可以将__LINE__
的使用改为__COUNTER__
(这是非标准的!)。感谢Quuxplusone的提示
答案 5 :(得分:1)
这是我在其他地方看到的另一个令人讨厌的伎俩。与我的其他答案相比,它有一个显着的缺点:你不能在相同的范围内使用它两次,因为它声明了一个变量。但是,对于其他情况,您希望在 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;
}
答案 6 :(得分:1)
我的日志设置非常相似:
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()将它作为单个命令刷新到日志输出并为其添加换行符。在我的实现中它始终如此,但是如果还没有条件,你可以使条件有条件。