不能保证每个平台都会以相同的方式定义固定宽度的整数类型,或者它们将在任何给定平台上根据基本类型来定义。因此,为确保您的重载能够捕获任何给定平台上的固定宽度类型,您需要确定它们在该平台上的实现方式。
虽然您可以使用模板技巧来做到这一点,但最简单的方法是使用一个独特的、最小的帮助程序,它输出每个固定宽度和基本类型的 typeid,允许您比较它们的内部名称来确定每个固定宽度类型是如何在该平台上和使用该编译器实现的。
#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;
}
示例输出:
// 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
从这里:
- MSVC(在 x86 和 x64 Windows 上,因为 ILP32 和 LLP64 使用相同的类型大小):我们可以看到固定宽度类型基于基本类型;请注意,对于 64 位整数类型,编译器将发出内部名称
__int64 (long long 之前的同义词被标准化,如 Bo Persson pointed out in the comments) 而不是规范名称 long long
- Clang 和 GCC(在 x64 *nix 上):通过比较重整的类型名称,我们可以看到:
- 8 位类型基于
char 类型。
- 16 位类型基于
short 类型。
- 32 位类型基于
int 类型。
- 64 位类型基于
long 类型。
由此,我们知道在这些平台上,使用这些编译器:
-
signed char 会赶上int8_t。
-
unsigned char 会赶上uint8_t。
-
signed short 会赶上int16_t。
-
unsigned short 会赶上uint16_t。
- 等等……
- [请注意,由于 Windows 的 LLP64 和 *nix 的 LP64 模型之间的差异,
int64_t 和 uint64_t 将被不同的重载捕获。]
然后,您可以将此过程应用于您可能希望使用的任何其他平台和编译器,以便您检测何时需要进行特定于平台的修改。
不过,这似乎是一个 XY 问题。您的主要问题是您希望能够在与基本类型不同的平台上为固定宽度类型重载,但不知道如何在不破坏它们所在平台上的代码的情况下执行此操作与基本类型相同。
为此,您需要找到一种唯一标识您所在平台的方法;最简单的方法是通过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
// ...
使用这样的设置,您可以为固定宽度类型不是基本类型的平台定义额外的重载,而不会影响它们是基本类型的平台。这将允许您在将它们交给您的基本类型重载之一(如有必要)之前进行任何特定于平台的处理。