Перво-наперво: микрооптимизация не нужна.Любой приличный компилятор с включенной оптимизацией преобразует a % b
в эту конструкцию, когда b
является постоянной времени компиляции, которая на самом деле является степенью 2.
Затем в конкретном утверждении вы можете использовать ту же конструкцию дляподтвердите это [*]:
BOOST_STATIC_ASSERT( !(size & (size-1)) );
[*] Обратите внимание, что, как указывает Матье М, это работает, только если 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 %
//...
};
В то же время утверждение о том, что инвариант хранится во время компиляции, важно для эффективности, поэтому скрытие кода не таково: просто оставьте операцию по модулю на месте, так как компилятор оптимизирует:
std::size_t hash_map::index_of( std::size_t hash ) const {
return hash % size;
}
Поскольку size
является постоянной времени компиляции, и это степень двух (вы утверждали, что раньше), оптимизатор переведет %
в оптимизированную операцию, в то время как код все еще читается людьми, которым требуетсяподдерживать его.