C++ 为什么std::基础_类型<;T>;当T不是时未签名?

C++ 为什么std::基础_类型<;T>;当T不是时未签名?,c++,c++11,enums,unsigned-integer,C++,C++11,Enums,Unsigned Integer,考虑一下这段琐碎的代码: int main() { enum Simple { one = 1, two = 2 }; Simple m1 = static_cast<Simple>(-1); if (m1 < 0) return -1; return 1; } intmain(){ 枚举简单{1=1,2=2}; 简单m1=静态_转换(-1); 如果(m1

考虑一下这段琐碎的代码:

int main() {
  enum Simple { one = 1, two = 2 };
  Simple m1 = static_cast<Simple>(-1);
  if (m1 < 0) return -1;
  return 1;
}
intmain(){
枚举简单{1=1,2=2};
简单m1=静态_转换(-1);
如果(m1<0)返回-1;
返回1;
}
毫不奇怪,结果是-1

令人惊讶的是,当我使用std::底层类型时,底层类型是“unsigned int”。世界跆拳道联盟?如果Simple的基础类型是unsigned,那么它是如何小于零的呢

进一步证据:

int main(int argc, char *argv[]) {
  enum Simple { one = 1, two = 2 };
  Simple m1 = static_cast<Simple>(-1);

  std::underlying_type<Simple>::type underlying = m1;

  long long llm1 = m1;

  std::cout << "simple=" << m1
            << " underlying=" << underlying
            << " long long=" << llm1
            << "\n";
}
intmain(intargc,char*argv[]){
枚举简单{1=1,2=2};
简单m1=静态_转换(-1);
std::基础类型\U类型::基础类型=m1;
长llm1=m1;

std::cout阅读文档

8) 整数、浮点或枚举类型可以转换为任何完整的枚举类型。如果转换为枚举基础类型的表达式的值超出范围,则结果为未指定(直到C++17)未定义行为(自C++17)(如果基础类型是固定的,则范围是类型的范围。如果基础类型不是固定的,则范围是足够大以容纳目标枚举的所有枚举数的最小位字段的所有可能值)


我敢打赌,隐式转换和整数提升的组合。甚至不编译的代码怎么能产生输出?没有
class
或显式基础类型的枚举的基础类型是实现定义的,除非枚举数无法匹配,否则它不允许是大于
int
的类型在
int
中,您的第一个示例显示了这一点(在C++17之前!)您的编译器使用了有符号类型作为基础类型。如果
std::undernative_type
实际解析为
unsigned int
,那么这两种情况的组合将表明编译器存在错误。但是,您应该根据您的代码发布一些证据,证明
std::undernative_type
实际上是
unsigned int
claimM.M第一个注释:代码确实编译并生成输出。M.M第二个注释:我的证据是查看生成的代码,请参阅。对输出m1的第一个调用调用基本的_ostream::operator对于非固定枚举(这是一个)来说,“range”的定义似乎有点不清楚,但
-1
将在任何签名的范围内bitfield@m.m.2位的无符号位字段足以存储1和2。2字节的有符号位字段则不能。通常,对于所有正枚举数的枚举,无符号位字段将比所需的有符号位字段小1位;因此,最小的位字段quired是唯一的,如果枚举数都是正数,则总是未签名。在其他新闻中,我很高兴看到
static\u cast(-1)
会导致硬盘驱动器在C++17中格式化。在我们看到编译器删除大块函数的第一种情况之前多久,因为它有一个代码路径指向它?@Yakk好的,我看到C++14有一个正式的定义。我猜这里引用的文本是对C++17草稿中类似的正式定义的解释。@m.m.好吧,这是一个错误代码打高尔夫很容易。只需引起UB,并提供一个编译器,可以在特定情况下执行任何需要的操作。