格式化宏以使用单行if语句

时间:2018-08-03 04:40:28

标签: c++ boost

我正在使用boost日志记录框架,该框架可能与该问题无关,但是我想使用LOG(sev)形式的宏,其中sev是日志级别之一,我可以标准化输出格式。

#define LOG_LOCATION \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<int>>(boost::log::core::get()->get_global_attributes()["Line"]).set(__LINE__); \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["File"]).set(__FILE__); \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["Function"]).set(__func__);

#define LOG(sev) LOG_LOCATION BOOST_LOG_SEV(slg, sev)

extern boost::log::sources::severity_logger<boost::log::trivial::severity_level > slg;

在大多数情况下,当日志位于一行时,此代码段有效,但是,如果我使用if格式的话。

if(false) LOG(debug) << "Don't print this";

它总是打印消息。原因很明显,if适用于宏中的第一个语句,其余语句已执行,因此该语句将显示(没有行号)。

我不确定如何格式化此宏以使其正常工作。

1 个答案:

答案 0 :(得分:1)

用逗号替换LOG_LOCATION宏中三个函数调用末尾的分号。这样会将三个语句变成一个局部语句,在扩展宏结束后继续。

#define LOG_LOCATION \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<int>>(boost::log::core::get()->get_global_attributes()["Line"]).set(__LINE__), \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["File"]).set(__FILE__), \
  boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["Function"]).set(__func__),

如上所用,if行将变为

if(false) a, b, c, BOOST_LOG_SEV(slg, sev) << "Don't print this";

(为简洁起见,用三个字母代替对set的三个呼叫。)

如果BOOST_LOG_SEV扩展为单个表达式,则可以使用。但是,BOOST_LOG_SEV扩展为for语句:

for (::boost::log::record rec_var = (logger).open_record((BOOST_PP_SEQ_ENUM(params_seq))); !!rec_var;)
    ::boost::log::aux::make_record_pump((logger), rec_var).stream()

因此有必要采用另一种方法。

您可以将“ LOG”定义为一个类(而不是宏),以将所有内容封装在这些宏中。

class LOG {
public:
    LOG(int sev): sev(sev) { LOG_LOCATION; }
    LOG &operator<<(const char *msg) {
        BOOST_LOG_SEV(slg, sev) << msg;
        return *this;
    }
}

根据您的需求,可以添加operator<<的其他重载来处理std::stringint,或者只是将其作为模板类。

在发送多个项目(LOG(debug) << "Number " << x << " found.")时,这可能不如原始的高效,但可以作为单个语句使用。