There is no guarantee that every platform will define the fixed-width integer types the same way, or that they'll be defined in terms of a fundamental type on any given platform. Therefore, to ensure that your overloads will catch fixed-width types on any given platform, you need to determine how they're implemented on that platform.
While you could do this with template tricks, the simplest way to do it is simply to use a distinct, minimal helper program, that outputs the typeid
of each fixed-width and fundamental type, allowing you to compare their internal names to determine how each fixed-width type is implemented on that platform & with that compiler.
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <typeinfo>
int main() {
std::cout << std::left;
std::cout << std::setw(10) << "int8_t: " << typeid(int8_t).name() << '\n'
<< std::setw(10) << "int16_t: " << typeid(int16_t).name() << '\n'
<< std::setw(10) << "int32_t: " << typeid(int32_t).name() << '\n'
<< std::setw(10) << "int64_t: " << typeid(int64_t).name() << '\n'
<< std::setw(10) << "uint8_t: " << typeid(uint8_t).name() << '\n'
<< std::setw(10) << "uint16_t: " << typeid(uint16_t).name() << '\n'
<< std::setw(10) << "uint32_t: " << typeid(uint32_t).name() << '\n'
<< std::setw(10) << "uint64_t: " << typeid(uint64_t).name() << '\n'
<< std::endl;
std::cout << std::setw(20) << "char: " << typeid(char).name() << '\n'
<< std::setw(20) << "signed char: " << typeid(signed char).name() << '\n'
<< std::setw(20) << "unsigned char: " << typeid(unsigned char).name() << '\n'
<< std::setw(20) << "signed short: " << typeid(signed short).name() << '\n'
<< std::setw(20) << "unsigned short: " << typeid(unsigned short).name() << '\n'
<< std::setw(20) << "signed int: " << typeid(signed int).name() << '\n'
<< std::setw(20) << "unsigned int: " << typeid(unsigned int).name() << '\n'
<< std::setw(20) << "signed long: " << typeid(signed long).name() << '\n'
<< std::setw(20) << "unsigned long: " << typeid(unsigned long).name() << '\n'
<< std::setw(20) << "signed long long: " << typeid(signed long long).name() << '\n'
<< std::setw(20) << "unsigned long long: " << typeid(unsigned long long).name() << '\n'
<< std::endl;
}
Example output:
// MSVC 2015 (x86 & x64):
int8_t: signed char
int16_t: short
int32_t: int
int64_t: __int64
uint8_t: unsigned char
uint16_t: unsigned short
uint32_t: unsigned int
uint64_t: unsigned __int64
char: char
signed char: signed char
unsigned char: unsigned char
signed short: short
unsigned short: unsigned short
signed int: int
unsigned int: unsigned int
signed long: long
unsigned long: unsigned long
signed long long: __int64
unsigned long long: unsigned __int64
// Clang & GCC (x64):
int8_t: a
int16_t: s
int32_t: i
int64_t: l
uint8_t: h
uint16_t: t
uint32_t: j
uint64_t: m
char: c
signed char: a
unsigned char: h
signed short: s
unsigned short: t
signed int: i
unsigned int: j
signed long: l
unsigned long: m
signed long long: x
unsigned long long: y
From this:
- MSVC (on both x86 & x64 Windows, since ILP32 & LLP64 use the same type sizes): We can see that fixed-width types are based on fundamental types; note that for 64-bit integral types, the compiler will emit the internal name
__int64
(a synonym from before long long
was standardised, as Bo Persson pointed out in the comments) instead of the canonical name long long
- Clang & GCC (on x64 *nix): By comparing mangled type names, we can see that:
- The 8-bit types are based on the
char
types.
- The 16-bit types are based on the
short
types.
- The 32-bit types are based on the
int
types.
- The 64-bit types are based on the
long
types.
From this, we know that on these platforms, with these compilers:
signed char
will catch int8_t
.
unsigned char
will catch uint8_t
.
signed short
will catch int16_t
.
unsigned short
will catch uint16_t
.
- And so on...
- [Note that due to differences between Windows' LLP64 and *nix's LP64 model,
int64_t
& uint64_t
will be caught by different overloads.]
You can then apply this process with any other platforms and compilers you may wish to use, allowing you to detect when you need to make platform-specific modifications.
This seems like an XY problem, though. Your main issue is that you want to be able to overload for the fixed-width types on platforms where they're distinct from the fundamental types, but don't know how to do this without breaking your code on platforms where they're the same as the fundamental types.
To do this, you'll need to find a way to uniquely identify the platform you're on; the easiest way to do this is by looking for macros specific to that platform.
void func( char);
void func( signed char);
void func(unsigned char);
void func( short);
void func(unsigned short);
// ...
#ifdef PLATFORM_WHERE_INT8_T_ISNT_SIGNED_CHAR
void func( int8_t);
void func(uint8_t);
#endif
#ifdef PLATFORM_WHERE_INT16_T_ISNT_SIGNED_SHORT
void func( int16_t);
void func(uint16_t);
#endif
// ...
Using a setup like that, you can define additional overloads for platforms where the fixed-width types aren't fundamental types, without affecting the platforms where they are fundamental types. This would allow you to do any platform-specific handling, before handing them off to one of your fundamental type overloads (if necessary).