【问题标题】:C++ primer enums and implicit conversionC++ 入门枚举和隐式转换
【发布时间】:2021-06-29 23:42:33
【问题描述】:

你好,我有这个来自 C++ 入门第 5 版:

// unscoped enumeration; the underlying type is machine dependent

enum Tokens {INLINE = 128, VIRTUAL = 129};

void newf(unsigned char);

void newf(int);

unsigned char uc = VIRTUAL;

newf(VIRTUAL); // calls newf(int)

newf(uc); // calls newf(unsigned char)

enum 令牌只有两个枚举器,其中较大的一个具有值129。该值可以用unsigned char 类型表示,许多编译器将使用unsigned char 作为Token 的底层类型。无论其基础类型如何,Tokens 的对象和枚举数都被提升为intenum 类型的枚举数和值不会提升为 unsigned char,即使枚举数的值适合。

  • 但是如果我明确指定与函数参数的整数值完全匹配的底层类型,那么我认为不会发生隐式转换:

    enum days : unsigned char{sat = 1, sun, mon, tue, wed, thu, fri};
    
    void foo(unsigned char x){
        std::cout << "foo(unsigned char)\n";
    }
    
    void foo(int){
       std::cout << "foo(int)\n";
    }
    
    foo(tue); // foo(unsigend char)
    

所以你可以看到枚举值tue 没有提升为int,我得到的是foo(unsigned char) 的版本而不是foo(int)

  • 那么他的意思是,如果枚举基础类型与函数参数不同,那么枚举数不会提升为char,而是提升为int 或大整数类型?

  • 我认为在他的enum tokens 示例中,如果底层类型是unsigned char,那么函数调用中将不会有整体提升:newf(VIRTUAL); // calls newf(int) 并且选择了newf(unsigned char) 的版本。你怎么看?

【问题讨论】:

  • 无关:为什么对一个十年前的编程文本的怪癖突然引起了人们的兴趣?大学最终决定将教学大纲更新到这个千年,但认为他们应该只进行一半吗?
  • “我认为不会发生隐式转换”。您是否尝试过自己运行代码?结果是否与您的预期不同,您想知道原因吗?结果是否符合您的预期,但您希望确认您的推理是正确的?
  • 我认为你把事情搞混了。对于具有未指定类型的enum,可能必须进行提升,但由于您没有使用具有未指定类型的enum,而是按名称要求unsigned charunsigned char 看起来更适合。可以推广,但这里没必要。
  • 也许我们都从最近的 C++ 标准来看它,无法真正理解这本书试图表达的观点。让我写一个 hack 示例来看看会发生什么。
  • 嗯。那里的编译器之间似乎存在很多分歧。似乎标准中的一些实际引用确实与此处相关。

标签: c++ enums implicit-conversion integer-promotion


【解决方案1】:

来自cppreference对enums的描述:

无范围枚举类型的值可以隐式转换为整数类型。如果基础类型不固定,则该值可转换为以下列表中能够保存其整个值范围的第一个类型:intunsigned intlongunsigned longlong long 或 @ 987654329@,具有更高转换等级的扩展整数类型(按等级顺序,有符号优先于无符号)(C++11 起)。如果基础类型是固定的,则可以将值转换为它们的基础类型(重载决议中首选),然后可以提升。

所以你对foo 的哪个重载将被选择是正确的,但你错了,没有发生隐式转换。 days 仍然是与 unsigned char 不同的类型,但它会隐式转换为一个。

如果实现恰好选择unsigned char 作为enum Tokens 的基础类型,那么您也错了,因此它将隐式转换为unsigned char。如果您自己修复底层类型而不是让实现来决定,则会隐式转换为比int更窄的底层类型。

您引用的 Primer 中的文字仅描述了您未明确指定基础类型时的情况。

来自draft standard,expr.conv.prom 的引用:

其基础类型不固定的无作用域枚举类型的纯右值可以转换为以下第一种类型的纯右值,该类型可以表示枚举的所有值([dcl.enum]):intunsigned intlong intunsigned long intlong long intunsigned long long int。如果该列表中的任何类型都不能表示枚举的所有值,则可以将无作用域枚举类型的纯右值转换为扩展整数类型的纯右值,其最低整数转换等级 ([conv.rank]) 大于long long 的等级,其中可以表示枚举的所有值。如果有两种这样的扩展类型,则选择有符号的。

其基础类型固定 ([dcl.enum]) 的无作用域枚举类型的纯右值可以转换为其基础类型的纯右值。此外,如果可以将整型提升应用于其基础类型,则其基础类型固定的无作用域枚举类型的纯右值也可以转换为提升的基础类型的纯右值。

来自over.ics.rank

提升其基础类型固定为其基础类型的枚举的转换优于提升为提升的基础类型的转换,如果两者不同的话。

【讨论】:

  • 所以我知道从枚举器(非范围枚举)到底层类型总是存在隐式转换。如果一个函数以int 为例,我们称它为传递一个无作用域enum 类型的枚举器,其基础类型例如为unsigned char,那么首先,枚举器值被隐式转换为(基础类型) unsigned char 然后提升为 int(整体提升)最终作为 int 参数传递给函数。对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多