Search code examples
c++bitset

What is this "operator" block of code in c++ class


I'm using someone's class for bitmaps, which are ways of storing chess positions in 64-bit bitsets. I was wondering what the part with auto() operator does. Is "auto" used because it returns one bit, which is why a return-type isn't specified for the function? I get that it checks that x and y are in the bounds of the chess board, and asserts an error if they aren't. I also understand that it returns a bit that corresponds to the x,y value pair for the bitset. I also don't get why the function is defined like it is, with an extra pair of parentheses. Any help is appreciated!

class BitBoard {
    private:
        std::bitset<64> board;
    public:
        auto operator()(int x, int y) {
            assert(0<=x && x<=7);
            assert(0<=y && y<=7);
            return board[8*y+x];
        }
    }
};

Solution

  • The "extra" pair of parentheses are because you're defining operator(), which lets instances of your class behave like functions. So if you had a:

    BitBoard board;
    

    you could get the value for x=3, y=5 by doing:

    board(3, 5)
    

    instead of having a method you call on the board explicitly, like board.get_bit_at(3, 5).

    The use of auto just means it deduces the return type from std::bitset<64>'s operator[]; since the method isn't const qualified, this means it's just deducing the std::bitset::reference type that std::bitset's operator[] uses to allow mutations via stuff like mybitset[5] = true;, even though you can't give "true" references to single bits. If reimplemented a second time as a const-qualified operator(), e.g.:

        auto operator()(int x, int y) const {
            assert(0<=x && x<=7);
            assert(0<=y && y<=7);
            return board[8*y+x];
        }
    

    you could use auto again for consistency, though it doesn't save any complexity (the return type would be bool in that case, matching std::bitset's const-qualified operator[], no harder to type than auto).

    The choice to use operator() is an old hack for multidimensional data structures to work around operator[] only accepting one argument; rather than defining operator[] to return a proxy type (which itself implements another operator[] to enable access to the second dimension), you define operator() to take an arbitrary number of arguments and efficiently perform the complete lookup with no proxies required.