对nullptr禁用BOOST_CHECK

时间:2019-02-06 10:34:57

标签: c++ boost nullptr boost-test

对于Boost Test早于1.64版,您不能执行以下操作:

SomeType* a_pointer = getPointer();
BOOST_CHECK_EQUAL(a_pointer, nullptr);

这是因为nullptr_t具有不明确的重载:Boost issue #12778a related SO question。就像在问题的答案中一样,这可以轻松解决:

BOOST_CHECK(!a_pointer); // rely on boolean casting, or...
// cast nullptr away from nullptr_t
BOOST_CHECK_EQUAL(a_pointer, static_cast<SomeType*>(nullptr));

但是,如果您支持多个增强版本,则BOOST_CHECK_EQUAL(a_pointer, nullptr)很容易在较新的平台上溜走,并破坏较旧的平台。

这里的一个解决方案是使用较旧的Boost版本强制实施CI平台(出于其他原因,该平台也很有用,尤其是当所支持的Boost版本在1.59之前扩展时,Boost Test 3发生了很大变化!)。

但是,仅依靠CI来捕获它是OODA循环中的一大延迟(与本地编译器故障相比),并且需要网络访问和简单但令人讨厌的VCS舞蹈来修补琐碎的更改并重新提交工作。

即使Boost版本会支持它,是否有办法导致它无法编译?

1 个答案:

答案 0 :(得分:3)

在Boost测试中,使用print_log_value commit 229e71199customization point中针对v1.64实现了这一点:

template<>
struct BOOST_TEST_DECL print_log_value<std::nullptr_t> {
    void operator()( std::ostream& ostr, std::nullptr_t t ) {
        ostr << "nullptr";
    }
};

不可能“取消定义”在另一个翻译单元中定义的功能(除非发生一些非常讨厌的预处理程序黑客攻击)。因此,如果您尝试使用该功能,实际上不可能“损坏”该功能并导致编译失败。

但是,我们有两个更好的选择:使用Boost测试方法来避免打印此类型,或者自己打印。


避免打印nullptr_t

您使用现有的Boost定制点来防止记录类型:BOOST_TEST_DONT_PRINT_LOG_VALUE

// in your common test header
BOOST_TEST_DONT_PRINT_LOG_VALUE( std::nullptr_t )

这是做什么的,因为在Boost 1.59中定义了一个print_log_value函数 什么都不做:

#define BOOST_TEST_DONT_PRINT_LOG_VALUE( the_type )         \
namespace boost{ namespace test_tools{ namespace tt_detail{ \
template<>                                                  \
struct print_log_value<the_type > {                         \
    void    operator()( std::ostream&, the_type const& ) {} \
};                                                          \
}}}                                                         \                                                     

在1.59(commit bae8de14b)之前,它的定义有所不同(开始时不在tt_detail中),但是思想是相同的。这意味着它将使用此宏至少恢复到1.58或更早的版本。

但是,因为在1.64中定义了print_log_value函数,所以,如果仅添加上面的宏,最终将导致从1.64开始的重新定义错误:DONT_PRINT宏不执行任何操作,并显示"nullptr"。因此,您可以使用相关的Boost版本来保护它:

#if BOOST_VERSION < 106400
    BOOST_TEST_DONT_PRINT_LOG_VALUE( std::nullptr_t )
#endif

现在它将避免在Boost <1.64上打印nullptr,而将在1.64+上打印:

[ != 0xdeadbeef]        // < 1.64, using BOOST_TEST_DONT_PRINT_LOG_VALUE
[nullptr != 0xdeadbeef] // 1.64 +, using built-in implementation

如果您真的不关心旧版Boost的登录效果,那么这可能就足够了。


自己动手

您还可以实现您自己的 print_log_value自定义点。但是,请注意,命名空间在1.59之前是不同的,并且我们仅应在<1.64之前使用它,因为再次,我们将重新定义函数:

// You don't need this bit if you don't support Boost Test <1.59.
#if BOOST_VERSION >= 105900
#    define BOOST_TEST_PRINT_NAMESPACE_OPEN namespace boost { namespace test_tools { namespace tt_details {
#    define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}}
#else
#    define BOOST_TEST_PRINT_NAMESPACE_OPEN namespace boost { namespace test_tools {
#    define BOOST_TEST_PRINT_NAMESPACE_CLOSE }}
#endif

#if BOOST_VERSION < 106400

BOOST_TEST_PRINT_NAMESPACE_OPEN

template<>
struct print_log_value<nullptr_t> {
    inline void operator()(std::ostream& os, nullptr_t const& p) {
        os << "nullptr";
    }
};

BOOST_TEST_PRINT_NAMESPACE_CLOSE

#endif // End <1.64 condition

现在它将打印相同的内容:

[nullptr != 0xdeadbeef] // < 1.64, using DIY implementation
[nullptr != 0xdeadbeef] // 1.64 +, using built-in implementation