c ++编译时断言

dbb*_*bbd 3 c++ boost assertions

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

#define REMAINDER(v, size) ((v) & (size -1))
Run Code Online (Sandbox Code Playgroud)

显然它假设大小是2的幂.

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

对我来说一个充分的测试就是大小总是一个常数(从不变量).

我会用BOOST_STATIC_ASSERT,但我无法弄清楚如何使用它来满足我的需要.

Dav*_*eas 6

首先要做的事情是:不需要微观优化.任何具有优化功能的合适编译器都将转换a % b为该构造,b而编译时常量实际上是2的幂.

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

BOOST_STATIC_ASSERT( !(size & (size-1)) );
Run Code Online (Sandbox Code Playgroud)

[*]请注意,正如Matthieu M指出的那样,只有size在无符号类型的情况下才有效.应该断言 - 在编译时不能断言参数是非负的较小要求:

BOOST_STATIC_ASSERT( (X(0)-1) > X(0) ); // where X is the type of the argument
Run Code Online (Sandbox Code Playgroud)

最后评论后编辑:

你错过了这一点.要使静态断言宏起作用,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 %
   //...
};
Run Code Online (Sandbox Code Playgroud)

同时声明在编译时保持不变量对于效率很重要,模糊代码不是:只需将模运算保留在原位,因为编译器将优化:

std::size_t hash_map::index_of( std::size_t hash ) const {
   return hash % size;
}
Run Code Online (Sandbox Code Playgroud)

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


Mar*_*k B 5

编辑:除非你有分析证明这是你的代码中的瓶颈,并且你的编译器没有适当地优化(v%8),只需编写明显的代码.

否则,因为你在这里处理整数,你可以使用模板而不是宏吗?然后你应该能够在模板内部静态断言,这样它就会在它被错误地实例化时标记出来.

例如:

template <int size>
int remainder(int v)
{
    BOOST_STATIC_ASSERT(!(size & (size - 1)));

    return v & (size -1);
};
Run Code Online (Sandbox Code Playgroud)