c++ - 为 nullptr 禁用 BOOST_CHECK
问题描述
使用早于 1.64 版的Boost Test,您不能这样做:
SomeType* a_pointer = getPointer();
BOOST_CHECK_EQUAL(a_pointer, nullptr);
这是因为nullptr_t
有模棱两可的重载:Boost issue #12778 and a 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 版本会支持它?
解决方案
在 Boost Test 中,这是在v1.64 的提交 229e71199中实现的,使用print_log_value
自定义点:
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.64print_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
推荐阅读
- javascript - 在服务器端访问反应路由参数
- c++ - Arduino HM-10 BLE 扫描仪开发
- object-detection - (Microsoft Azure 自定义视觉服务:对象检测)如何找到训练数据的边界框信息?
- c# - 在 C# 中使用 Laravel 模型工厂
- python - 如何为具有明确时间戳的时间序列数据构建数据框?
- ios - Firebase Facebook 登录 - 检测用户登录状态并重定向
- excel - 如何在数据透视表上从总和切换到平均值?
- angular - 带有后端验证流程说明的 Google 登录
- python - 向类添加方法时PyCharm“未使用的导入语句”
- ios - iOS 上的 FormatException 无效的 HTTP 标头 Flutter