I realize that there is a rule by which numbers with a width smaller than int
can be promoted to a wider type for the addition operation. But I cannot fully explain how only one permutation of the following print_unsafe_minus
will fail. How is it that only the <unsigned, long>
example fails, and what is the take-away for programmers with regards to best practices?
#include <fmt/core.h>
template<typename M, typename N>
void print_unsafe_minus() {
M a = 3, b = 4;
N c = a - b;
fmt::print("{}\n", c);
}
int main() {
// storing result of unsigned 3 minus 4 to a signed type
print_unsafe_minus<uint8_t, int8_t>(); // -1
print_unsafe_minus<uint16_t, int8_t>(); // -1
print_unsafe_minus<uint32_t, int8_t>(); // -1
print_unsafe_minus<uint64_t, int8_t>(); // -1
print_unsafe_minus<uint8_t, int16_t>(); // -1
print_unsafe_minus<uint16_t, int16_t>(); // -1
print_unsafe_minus<uint32_t, int16_t>(); // -1
print_unsafe_minus<uint64_t, int16_t>(); // -1
print_unsafe_minus<uint8_t, int32_t>(); // -1
print_unsafe_minus<uint16_t, int32_t>(); // -1
print_unsafe_minus<uint32_t, int32_t>(); // -1
print_unsafe_minus<uint64_t, int32_t>(); // -1
print_unsafe_minus<uint8_t, int64_t>(); // -1
print_unsafe_minus<uint16_t, int64_t>(); // -1
print_unsafe_minus<uint32_t, int64_t>(); // 4294967295
print_unsafe_minus<uint64_t, int64_t>(); // -1
}
(edit) Also worth noting-- if we extend the example to include 128-bit integers, then the following two permutations fail as well:
print_unsafe_minus<uint32_t, __int128>(); // 4294967295
print_unsafe_minus<uint64_t, __int128>(); // 18446744073709551615