C++ 编译时断言

标签 c++ boost assertions

我正在使用一个可能有危险的宏:

#define REMAINDER(v, size) ((v) & (size -1))

显然它假定大小是 2 的幂。

我想确保大小确实是 2 的幂,但在编译时。 (在运行时测试很容易,但不是我想要的)。

对我来说,一个充分的测试是大小始终是一个常数(绝不是变量)。

我会使用 BOOST_STATIC_ASSERT,但我不知道如何使用它来满足我的需要。

最佳答案

首先要做的是:不需要微优化。当 b 是一个编译时间常量,实际上是 2 的幂时,任何启用了优化的体面的编译器都会将 a % b 转换成该结构。

然后在特定断言上,您可以使用相同的构造来断言它 [*]:

BOOST_STATIC_ASSERT( !(size & (size-1)) );

[*] 请注意,正如 Matthieu M 指出的那样,这仅在 size 是无符号类型时才有效。并且应该断言——参数为非负的较小要求不能在编译时断言:

BOOST_STATIC_ASSERT( (X(0)-1) > X(0) ); // where X is the type of the argument

在最后评论后编辑:

你没有捕获要点。要使静态断言宏起作用,size 必须是编译时常量。如果它是一个编译时常量,那么只需在定义常量时断言,这也是最好的地方,因为它将用作文档,并将指向需要修改的精确代码点:

template <typename N>
class hash_map {
public:
   const std::size_t size = N;
   BOOST_STATIC_ASSERT( !(size & (size-1) ) ); // N must be power of 2 for fast %
   //...
};

与此同时,断言在编译时保持不变量对于 boost 效率很重要,但混淆代码并不重要:只需保留模运算,因为编译器会优化:

std::size_t hash_map::index_of( std::size_t hash ) const {
   return hash % size;
}

因为 size 是一个编译时间常量,它是二的幂(你之前断言过)优化器会将 % 转换为优化操作,而需要维护它的人仍然可以阅读代码。

关于C++ 编译时断言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5183307/

相关文章:

c++ - lua_status 能否检测函数在使用 lua_call 调用后是否产生?

C++:围绕平面法线旋转 vector

c++ - 为什么 Boost Log 记录器操作不是常量?

c++ - 针对boost::uuid的Valgrind日志分析

ruby-on-rails - 在 Rails 中的测试之外使用断言

c++ - "int main(){(([](){})());}"如何是有效的 C++?

c++ - boost::interprocess::managed_shared_memory 崩溃程序

c++ - 使用 copyTo 函数断言失败 (C++)

c++ - 断言总是不好的吗?

c++ - 全局范围 LPWSTR 在更改后恢复