我正在开发国际象棋引擎,并致力于移动生成。例如,这是我为黑骑士生成 Action 的函数:
/** Pseudolegal moves don't take check into account. */
std::vector<uint8_t>
generate_pseudolegal_bknight_moves(std::shared_ptr<Position> position,
uint8_t square) {
assert(VALID_SQUARE(square));
assert(position->mailbox[square] == B_KNIGHT);
uint8_t candidates[8] = {
NEXT_RANK(PREV_FILE(PREV_FILE(square))),
NEXT_RANK(NEXT_RANK(PREV_FILE(square))),
PREV_RANK(PREV_FILE(PREV_FILE(square))),
PREV_RANK(PREV_RANK(PREV_FILE(square))),
NEXT_RANK(NEXT_FILE(NEXT_FILE(square))),
NEXT_RANK(NEXT_RANK(NEXT_FILE(square))),
PREV_RANK(NEXT_FILE(NEXT_FILE(square))),
PREV_RANK(PREV_RANK(NEXT_FILE(square))),
};
std::vector<uint8_t> moves;
for (int i = 0; i < 8; i++) {
uint8_t candidate = candidates[i];
uint8_t piece = position->mailbox[candidate];
if (VALID_SQUARE(candidate) && (!IS_BLACK_PIECE(piece))) {
moves.push_back(candidate);
}
}
return moves;
}
生成白色骑士 Action 的功能非常相似,只改变了两个术语(宏):B_KNIGHT
-> W_KNIGHT
和IS_BLACK_PIECE
-> IS_WHITE_PIECE
。我不希望本质上为每一个片段都复制移动生成函数,但是到目前为止,因为它具有最小的运行时开销,所以一直都在这样做。
我可以在args中包含
bool is_white
或其他内容,并使用三元is_white ? W_KNIGHT : B_KNIGHT
切换条件,但是条件条件会在运行时增加以前没有的开销,而且看起来并不那么优雅。我想知道是否有一些编译时功能可以帮助我定义一个函数。我想我也可以使用内联函数来尝试减少重复代码的数量,但是我想知道是否有任何替代方法比这更好。
最佳答案
如果您不想增加开销,可以使用template参数和if constexpr
:
enum class Color { WHITE, BLACK };
template <Color C> std::vector<uint8_t>
generate_pseudolegal_knight_moves(std::shared_ptr<Position> position,
uint8_t square) {
...
if constexpr (C == Color::WHITE) {
assert(position->mailbox[square] == W_KNIGHT);
} else {
assert(position->mailbox[square] == B_KNIGHT);
}
...
}
// Call
auto moves = generate_pseudolegal_knight_moves<Color::WHITE>(...);
该标准保证条件将在编译时评估,并且错误分支将被丢弃。
关于c++ - 如何在不声明C/C++附加功能的情况下对代码进行重复数据删除?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64814789/