Boost Log的琐碎记录器的“懒惰评估”如何工作?

时间:2018-05-15 15:44:41

标签: c++ boost lazy-evaluation boost-log

[跟进Check boost::log filter explicitly? ]

以下示例使用Boost Log中的普通记录器。它输出1,表示expensive()只被调用一次。它是如何工作的?为什么expensive()没有被调用?

Live On Coliru

#include <iostream>

#include <boost/log/expressions.hpp>
#include <boost/log/trivial.hpp>

int count = 0;

int expensive()
{
    return ++count;
}

int main()
{
    boost::log::core::get()->set_filter(
        boost::log::trivial::severity >= boost::log::trivial::warning
    );

    BOOST_LOG_TRIVIAL(error) << expensive();
    BOOST_LOG_TRIVIAL(info) << expensive();

    std::cout << count << '\n';

    return 0;
}

输出:

[2018-05-21 14:33:47.327507] [0x00007eff37aa1740] [error]   1
1

1 个答案:

答案 0 :(得分:6)

它通过使用一点宏/预处理器魔法来工作。这些语句看起来确实像对某些operator<<()的函数调用:

BOOST_LOG_TRIVIAL(warning) << expensive();

然而,简化很多,宏的工作就好像我们写了类似的东西:

if (level == warning)
    logger << expensive();

如果你想简化代码以避免一直写,你可以像这样定义一个宏:

#define LOG_WARNING if (level == warning) logger

然后我们可以将它用作:

LOG_WARNING << expensive();

实际的BOOST_LOG_TRIVIAL宏最终会扩展为:

for (
    ::boost::log::record _boost_log_record_N =
        (::boost::log::trivial::logger::get()).open_record(
            (::boost::log::keywords::severity = ::boost::log::trivial::error)
        )
    ;
    !!_boost_log_record_N;
)
    ::boost::log::aux::make_record_pump(
        (::boost::log::trivial::logger::get()),
        _boost_log_record_N
    ).stream() << expensive();

如您所见,根据!!_boost_log_record_N循环条件(进而取决于open_record()的结果),循环体将运行零次或多次;这就是expensive()并不总是运行的原因。