用于数据记录的C ++ #define宏

时间:2016-05-14 21:44:42

标签: c++ macros

我有一个vlog类,负责打印程序中的所有日志消息。每个类都可以包含vlog.h标头,然后使用以下代码记录数据:

{
    std::lock_guard<std::mutex> lock(vlog::lock_log);
    vlog::EVENT(host) << "hello" << " world!" << std::flush;
}

我想将上面的代码更改为这样的简单宏:

EVENT_LOG_C(host) << "hello" << " world!" << std::flush;

宏应首先调用lock_guard,然后将消息传递给vlog :: EVENT(host)对象。我该如何定义宏?

编辑:我希望整个日志msg(可能包含多个&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; <<的每次使用都会调用静态对象,我无法将lock_guard放入vlog类本身。

2 个答案:

答案 0 :(得分:4)

只需将std::lock_guard填入宏中,但将其作为日志记录表达式的一部分:

#define EVENT_LOG_C(host) \
    std::lock_guard<std::mutex>{vlog::lock_log}, vlog::EVENT(host)

其中的逗号运算符确保在右侧发生任何事件之前构造临时锁,并且它将一直存在直到分号结束。

你也可以通过让第一个operator <<返回一个锁定代理来摆脱宏,然后转发每个跟随<<直到表达式结束。

// Simple wrapper around the std::lock_guard to ease operator overloading
struct EventLogLocker {
    EventLogLocker(std::mutex &mtx)
    : lck{mtx} { }

    std::lock_guard<std::mutex> lck;
};

// Perfect-forwarding operator << that hooks on the EventLogLocker
template <class T>
EventLogLocker const &operator << (EventLogLocker const &ell, T &&obj) {
    // Log here
    std::cout << std::forward<T>(obj);
    return ell;
}

// operator << for iostream manipulators (these can't be deduced by the
// template above because they're overloaded for different stream types)
EventLogLocker const &operator << (
    EventLogLocker const &ell,
    std::ostream &(*manip)(std::ostream &)
) {
    std::cout << manip;
    return ell;
}

// Stub function, the important thing is to return an EventLogLocker by value
EventLogLocker EVENT_LOG_C(...) {
    return {lock_log};
}

答案 1 :(得分:1)

您需要做的就是将互斥锁锁定在支持流操作的类的构造函数中,并在析构函数中释放互斥锁。

不需要宏。

例如;

  namespace vlog
  {
       class EVENT
       {
          public:

           EVENT() : event_lock(vlog::lock_log)
           {

           };

           template<class T> EVENT &operator<<(const T &v)
           {
               std::cerr << v;
               return *this;
           };            

           private:

              std::lock_guard<std::mutex> event_lock;

       };
  }

在上面,为了便于讨论,我假设您的日志记录将是std::cerr,并且EVENT的构造函数不接受任何参数。这很容易改变。

然后您需要做的就是

   vlog::EVENT() << "hello" << "world" << std::flush;

本声明的工作原则是首先构建vlog::EVENT。构造函数抓取互斥锁。然后在每次流操作期间继续抓取互斥锁。在语句的末尾(实际上是其中的表达式),vlog::EVENT对象将被销毁,并且在销毁期间锁将被释放。

如果要将互斥锁锁定在多个语句上,只需将临时绑定到引用即可。这将对象的生命周期附加到引用的生命周期。或者构造一个命名对象。