The following code compiles warning-less on a 64-bit Linux system using (native 64-bit) g++-10:
#include <cstdint>
class A {
public:
explicit A(unsigned long long int x) { };
explicit A(uint64_t x) { };
};
int main() {}
However, on a 32-bit system, (same Linux distro, same version, but it is a 32-bit machine), I get this error:
t.cc:6:14: error: ‘A::A(uint64_t)’ cannot be overloaded with ‘A::A(long long unsigned int)’
6 | explicit A(uint64_t x) { };
| ^
t.cc:5:14: note: previous declaration ‘A::A(long long unsigned int)’
5 | explicit A(unsigned long long int x) { };
I tested the bitsizes experimentally (printf-ing sizeof(long long unsigned int)
), and yes they are all 8 byte long on both 32 and 64 bit systems.
Why it then does not compile on a 32-bit system?
Extension:
I hunted a little bit for that, and I found in the glibc headers /usr/include/x86_64-linux-gnu/bits/types.h
(or /usr/include/i386-linux/bits/types.h
) that their defition differs by an __extension__
macro or attribute:
#if __WORDSIZE == 64
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#else
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
#endif
I think this __extension__
is the important thing. If __WORDSIZE == 64
, thus we are on a 64-bit environment, then these types are compatible. If not, then the type definitions differ by an __extension__
. Where is this attribute (macro) from? How to make fair platform-independent code?
uint64_t
is not a fundamental type. It is an optional "type" that is an alias to a unsigned integer type that is 64 bits wide. On your 32 bit system, that means most likely that they have it defined like
using uint64_t = unsigned long long int;
so they are they same type, and you can't have two overloads with the same signature
On your 64 bit machine, most likely they use unsigned long int
instead since that is 64 bits on 64 bit linux distros. That's why it works for 64 bits but not 32 bits.