Earlier we found ourselves writing code for a bitmap based chess engine which when finding pseudo-legal moves required bit shifting in different directions based on the color of the pawn. 


#include <cstdint>


void getLegalChessMoves(bool isForWhite, Board* board) {

  uint64_t attacks, pushes;

  for (uint64_t mask = /*...*/) {

    if (isForWhite) {

      attacks = ((mask << 9) | (mask << 7));

      pushes = (mask << 8) & board->emptySquares;

       // ...

    } else {

      attacks = ((mask >> 9) | (mask >> 7));

      pushes = (mask >> 8) & board->emptySquares;

      // ...

    }

  }

}



One way of deduplicating this would be to treat the bit shifts as function objects and switch the used function depending on the isForWhite condition, like so:



#include <cstdint>

#include <functional>


void getLegalChessMoves(bool isForWhite, Board* board) {

  uint64_t attacks, pushes;

  auto shift = isForWhite ? std::function<uint64_t(uint64_t, uint64_t)>(std::shift_left<>()) : std::function<uint64_t(uint64_t, uint64_t)>(std::shift_right<>());

  for (uint64_t mask = /*...*/) {

      attacks = (shift(mask, 9) | shift(mask, 7));

      pushes = shift(mask, 8) & board->emptySquares;

      // ...

  }

}


However, we were surprised to find that there is no functional object for left and right bit shifts in <functional>, even though every other binary operator in C++ has a corresponding functional object! A workaround for this is of course to define the function ourselves:


auto shift = isForWhite ? [](uint64_t a, uint64_t b) { return a << b; } : [](uint64_t a, uint64_t b) { return a >>b; };


…but such a lambda can already be used in place of any binary operator functor, and the <functional> header feels incomplete without an implementation of the std::shift_left and std::shift_right functors. We propose adding the aforementioned functors with a similar implementation to the currently defined binary operator functors.


Proposed Changes:


To 22.10.11 [function.objects], Function objects, paragraph 2, add to the header <functional> synopsis:


template <class T = void> struct shift_left;

template <class T = void> struct shift_right;

template<> struct shift_left<void>;

template<> struct shift_right<void>;


The library provides basic function object classes for all of the bitwise operators in the language ([expr.shift] 7.6.7)

template <class T> struct shift_left {

  T operator()(const T&x , const T&y ) const;

};

constexpr T operator()(const T& x, const T& y) const; 

operator() returns x << y


template <class T> struct shift_right  {

  T operator()(const T&x , const T&y ) const;

};

constexpr T operator()(const T& x, const T& y) const; 

operator() returns x >> y


Cheers,

~ Andrew and Leon