The only portable way is to use memcpy
(yes, I know what you're thinking, and no it's not inefficient).
Note that this solution does not take into account byte-ordering. You'd need to cater for that too to be strictly portable.
#include <cstdlib>
#include <cstring>
#include <utility>
#include <iostream>
// only compile this function if Integer is the same size as a double
template<class Integer, std::enable_if_t<sizeof(Integer) == sizeof(double)>* = nullptr>
double or_bits(double input, Integer bits)
{
Integer copy;
// convert the double to a bit representation in the integer
std::memcpy(©, &input, sizeof(input));
// perform the bitwise op
copy |= bits;
// convert the bits back to a double
std::memcpy(&input, ©, sizeof(copy));
// return the double
return input;
}
int main()
{
double d = 1.0;
d = or_bits(d, 0x10ul);
std::cout << d << std::endl;
}
assembly output on gcc5.3:
double or_bits<unsigned long, (void*)0>(double, unsigned long):
movq %xmm0, %rax
orq %rdi, %rax
movq %rax, -8(%rsp)
movsd -8(%rsp), %xmm0
ret