c++ - 为 nullptr 禁用 BOOST_CHECK

标签 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 版本,BOOST_CHECK_EQUAL(a_pointer, nullptr) 很容易在较新的平台上溜走,并破坏旧平台。

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

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

有没有办法让它编译失败,即使 Boost 版本支持它?

最佳答案

在 Boost 测试中,这是在 commit 229e71199 中实现的对于 v1.64,使用 print_log_value customization point :

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

关于c++ - 为 nullptr 禁用 BOOST_CHECK,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54551512/

相关文章:

c++ - 派生类不从基类继承重载方法

c++ - 是为 C++ 中的默认构造函数创建的汇编代码

c++ - 使用 qt 自定义委托(delegate)正确突出显示

c++ - 为什么我会看到此消息 "library not found for -lboost_system"?

c++ - 在 API 函数调用中使用 nullptr?

c++ - {} 构造语法有多通用?

c++ - 标准线程库与 Boost 相比如何?

c++ - 如何在多线程中安全地使用 boost deadline timer?

c++ - 为什么 std::nullptr_t 在 C++ 中不能与 std::cout 一起使用?

c++ - 非空原始指针和 nullptr 之间的运算符小于