如何在不在 C/C++ 中声明附加函数的情况下删除重复代码?
How can I de-duplicate code without declaring an additional function in C/C++?
我正在开发国际象棋引擎并致力于移动生成。例如,这是我为黑骑士生成动作的函数:
/** 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;
}
生成白马走法的函数非常相似,只是两个项(宏)发生了变化:
B_KNIGHT
-> W_KNIGHT
,以及 IS_BLACK_PIECE
-> IS_WHITE_PIECE
。
我不希望在本质上为每一块重复移动生成函数,但到目前为止一直这样做,因为它具有最小的运行时开销。
我可以在 args 中包含 bool is_white
或其他内容,并使用三元 is_white ? W_KNIGHT : B_KNIGHT
切换术语,但条件会在运行时增加以前不存在的开销,而且看起来并不那么优雅。我想知道是否有一些编译时功能可以帮助我定义一个函数。
我想我也可以使用内联函数来尝试减少重复代码的数量,但我想知道是否有比这更好的选择。
如果你不想开销,你可以使用模板参数和 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>(...);
标准保证条件将在编译时进行评估,错误的分支将被丢弃。
我正在开发国际象棋引擎并致力于移动生成。例如,这是我为黑骑士生成动作的函数:
/** 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;
}
生成白马走法的函数非常相似,只是两个项(宏)发生了变化:
B_KNIGHT
-> W_KNIGHT
,以及 IS_BLACK_PIECE
-> IS_WHITE_PIECE
。
我不希望在本质上为每一块重复移动生成函数,但到目前为止一直这样做,因为它具有最小的运行时开销。
我可以在 args 中包含 bool is_white
或其他内容,并使用三元 is_white ? W_KNIGHT : B_KNIGHT
切换术语,但条件会在运行时增加以前不存在的开销,而且看起来并不那么优雅。我想知道是否有一些编译时功能可以帮助我定义一个函数。
我想我也可以使用内联函数来尝试减少重复代码的数量,但我想知道是否有比这更好的选择。
如果你不想开销,你可以使用模板参数和 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>(...);
标准保证条件将在编译时进行评估,错误的分支将被丢弃。