C ++ compile time statement

I use a macro that can be dangerous:

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

obviously, he suggests that the size is 2.

I would like to make sure the size is really 2, but at compile time. (runtime testing is easy, but NOT what I want).

A sufficient test for me would be that size is always a constant (never variable).

I would use BOOST_STATIC_ASSERT, but I can’t figure out how to use it for what I need.

+3
source share
5 answers

: . a % b , b , 2.

[*]:

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

EDIT :

. 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 %
   //...
};

, , , , : modulo , :

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

size - , ( , ) % , - , .

+6

EDIT: , , (v% 8), .

, , ? , , .

, - :

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

    return v & (size -1);
};
+5

:

size && (size & (size - 1) == 0)

EDIT: .

, . 1 , . ANDing 0.

, . 1 , . ANDing 0, () .

1000 & 0111 == 0000
1100 & 1011 == 1000
+3
// Only use this if size is a power of 2
#define REMAINDER(v, size) ((v) & (size -1))

. .


, , :

template <size_t SIZE>
size_t remainder(size_t v) {
   // Perform whatever assertions you like on SIZE here

   return v & (SIZE - 1);
}

, .

+2

Peephole:

:

Now let's look at an example of this using the LLVM backend optimizer :

// C
int iremainder(int i) { return i % 4; }

unsigned uremainder(unsigned u) { return u % 4; }

// LLVM IR
define i32 @iremainder(i32 %i) nounwind readnone {
entry:
  %0 = srem i32 %i, 4                             ; <i32> [#uses=1]
  ret i32 %0
}

define i32 @uremainder(i32 %u) nounwind readnone {
entry:
  %0 = and i32 %u, 3                              ; <i32> [#uses=1]
  ret i32 %0
}

Analyze, could you?

  • u / 4gives and i32 %u, 3(which is translated to C gives u & 3)
  • i / 4gives srem i32 %i, 4(which is translated to C gives i % 4)

What is an intelligent compiler ! He did not forget that performing bitwise operations with the sign of integers will not give the result that I wanted (whenever the integer is negative and the branches are more expensive than division).

Moral: Such optimization is almost useless, and you are even mistaken.

+1
source

Source: https://habr.com/ru/post/1796079/


All Articles