20
my_macro << 1 << "hello world" << blah->getValue() << std::endl;

应扩展为:

std::ostringstream oss;
oss << 1 << "hello world" << blah->getValue() << std::endl;
ThreadSafeLogging(oss.str());
4

7 回答 7

76
#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<<. 可惜点赞不能分享。

于 2010-02-03T23:02:22.017 回答
3

难道你不能从 ostream 派生并提供你自己的线程安全实现吗?然后你可以做

myCOutObject << 1 << "hello world" << blah->getValue() << std::endl;

并在没有宏的情况下获得完全相同的功能并正确使用 C++?

于 2010-02-03T23:03:04.733 回答
2

不可以。问题在于,如果不使用函数语法,宏仅限于被替换它所在的位置。

但是,如果您愿意使用函数语法,则可以在 args 之前和之后替换东西。

my_macro(1 << "hello world" << blah->getValue() << std::endl);

您可以通过将 MyMacro 定义为:

#define my_macro(args) std::ostreamstring oss; \
                       oss << args; \
                       ThreadSafeLogging(oss.str());
于 2010-02-03T23:01:26.373 回答
2

看看google-glog,他们使用一个临时对象来实现这一点

LOG(INFO) << "log whatever" << 1;

他们还有其他有趣的宏,例如 LOG_IF 等。

于 2010-02-03T23:09:26.140 回答
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; 
} 

由于 operator 的简单性,Developper 可能不需要在同一行上使用此宏两次<<。但是如果你需要这个,你可以切换使用__LINE__by __COUNTER__(这是非标准的!)。感谢 Quuxplusone 的提示

于 2010-03-16T17:29:40.717 回答
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;
}
于 2010-02-05T23:05:17.953 回答
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() 将其作为单个命令刷新到日志输出并添加换行符. 在我的实现中它总是这样,但如果还没有的话,你可以让它有条件。

于 2017-07-06T06:40:55.197 回答