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];
}
}
};
CodePudding user response:
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_as(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.
CodePudding user response:
operator()
is the name of the function, which is then followed by another pair of parentheses listing the arguments. It is the function-call operator and overloading it allows you to make objects that act like functions/function pointers. In this case, it allows:
BitBoard thing;
thing(i, j); // looks like a function!
In this particular case, it's being used for indexing (like a[i]
) but the subscript operator operator[]
doesn't allow multiple indexes and the function-call operator does. So it was pretty common to see this for multi-dimensional arrays.
However, the new "preferred" style for multiple indexes in C is to pass a list to the subscript operator:
BitBoard thing;
std::cout << thing[{i, j}];
This would be accomplished by operator[](std::array<int, 2> xy)
.
But the author of this class has chosen the old way, that looks like a function call.
Overloaded operator()
is also what makes lambda expressions tick inside.