Tengo un código que es más o menos así:
#include <bitset>
enum Flags { A = 1, B = 2, C = 3, D = 5,
E = 8, F = 13, G = 21, H,
I, J, K, L, M, N, O };
void apply_known_mask(std::bitset<64> &bits) {
const Flags important_bits[] = { B, D, E, H, K, M, L, O };
std::remove_reference<decltype(bits)>::type mask{};
for (const auto& bit : important_bits) {
mask.set(bit);
}
bits &= mask;
}
Clang> = 3.6 hace lo inteligente y lo compila en una sola and
instrucción (que luego se inserta en cualquier otro lugar):
apply_known_mask(std::bitset<64ul>&): # @apply_known_mask(std::bitset<64ul>&)
and qword ptr [rdi], 775946532
ret
Pero cada versión de GCC que he probado compila esto en un lío enorme que incluye el manejo de errores que debería ser DCE estáticamente. En otro código, ¡incluso colocará el important_bits
equivalente como datos en línea con el código!
.LC0:
.string "bitset::set"
.LC1:
.string "%s: __position (which is %zu) >= _Nb (which is %zu)"
apply_known_mask(std::bitset<64ul>&):
sub rsp, 40
xor esi, esi
mov ecx, 2
movabs rax, 21474836482
mov QWORD PTR [rsp], rax
mov r8d, 1
movabs rax, 94489280520
mov QWORD PTR [rsp+8], rax
movabs rax, 115964117017
mov QWORD PTR [rsp+16], rax
movabs rax, 124554051610
mov QWORD PTR [rsp+24], rax
mov rax, rsp
jmp .L2
.L3:
mov edx, DWORD PTR [rax]
mov rcx, rdx
cmp edx, 63
ja .L7
.L2:
mov rdx, r8
add rax, 4
sal rdx, cl
lea rcx, [rsp+32]
or rsi, rdx
cmp rax, rcx
jne .L3
and QWORD PTR [rdi], rsi
add rsp, 40
ret
.L7:
mov ecx, 64
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:.LC1
xor eax, eax
call std::__throw_out_of_range_fmt(char const*, ...)
¿Cómo debo escribir este código para que ambos compiladores puedan hacer lo correcto? De no ser así, ¿cómo debería escribir esto para que quede claro, rápido y fácil de mantener?
(1ULL << B) | ... | (1ULL << O)
(1ULL << Constant)
| por línea, y alinee los nombres de las constantes en las diferentes líneas, eso sería más fácil para los ojos.
int
resultado de la operación de bits PUEDE SER int
O puede long long
depender del valor y formalmente enum
no es equivalente a una int
constante. clang pide "como si", gcc sigue siendo pedante
B | D | E | ... | O
?