为什么具有固定底层类型char的枚举值会解析为fct(int)而不是fct(char)?

时间:2013-01-08 00:22:53

标签: c++ c++11 enums overloading overload-resolution

回答this question about overload resolution with enums时出现了这个问题。

虽然long long的情况绝对是MSVC2012NovCTP中的错误(根据标准文本和gcc 4.7.1的测试),但我无法弄清楚为什么会出现以下行为:

#include <iostream>

enum charEnum : char { A = 'A' };

void fct(char)      { std::cout << "fct(char)"      << std::endl; }
void fct(int)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    fct('A');
    fct(A);
}

MSVC2012NovCTP和gcc 4.7.1都同意此输出:

  

FCT(炭)
  fct(int)

不应AcharEnum转换为char吗?为什么A被转换为int

编辑:clang抱怨说这个电话含糊不清,这与我在下面的解释一致;那说,如果它只被认为是潜在的类型,我仍然会发现它更直观。


两个相关的标准摘录是§7.2/ 9:

  

通过整数提升(4.5)将枚举数或无范围枚举类型的对象的值转换为整数

并且§4.5/ 4:

  

其底层类型为固定(7.2)的未作用域枚举类型的prvalue可以转换为其基础类型的prvalue。此外,如果可以将整数提升应用于其基础类型,则其基础类型固定的未范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue。

因此,charEnum可以转换为char,也可以转换为char的任何整体推广,例如int

但这对我来说很模糊,因为“可以”并不能说实际上会选择哪一个。如果有的话,这个措辞应该含糊不清,因为在char或其任何促销活动之间没有给出优先权。如果您注释掉fct(int),那么的调用是不明确的。为什么int特别?

我唯一能想到的是递归推广整体促销活动,但我认为没有任何要求。

2 个答案:

答案 0 :(得分:9)

在C ++ 03中,规则是:

  

无范围枚举类型的右值(7.2 [dcl.enum])可以   转换为可以的以下第一种类型的右值   表示枚举的所有值(即,枚举中的值)   范围bmin到bmax,如7.2 [dcl.enum]中所述):int,unsigned int,   long int,unsigned long int,long long int或unsigned long long int。

在C ++ 03编译器中,将选择int,因为它是第一个 在名单上。


在C ++ 11中,引入了底层类型。因此,通过685. Integral promotion of enumeration ignores fixed underlying type ,这个措辞改为§4.5/ 4中引用的段落,并且从阅读缺陷报告开始,委员会的意图似乎是fct(char)(基础类型)被选中。

但是,根据core issue 1601下的讨论,C ++ 11中的文字实际上使转换变得模糊(fct(char)fct(int)都是可能的,并且两者都不是首选。)< / p>

以下修正案被提出并被C ++ 14接受:

  

促进其基础类型为的枚举的转换   固定到它的底层类型比促进它的一个更好   如果两者不同,则提升基础类型。

由于它被报告为C ++ 11中的缺陷,编译器应该在C ++ 11模式下应用此修复并调用fct(char)

答案 1 :(得分:3)

根据我对当前标准的解释,呼叫必须含糊不清。遵循解释。

每4.5 / 4:

“其底层类型固定的无范围枚举类型的prvalue(7.2)可以转换为其基础类型的prvalue。此外,如果可以将整数提升应用于其基础类型,则可以使用它的prvalue。其基础类型固定的未作用域枚举类型也可以转换为升级基础类型的prvalue。“

这提供了两种替代促销:对基础类型的促销,以及对提升的基础类型的促销。因此,这个段落单独引入了歧义,因为在解析对重载函数的函数调用时应该使用这些替换的

然后,第13.3.3段根据“转换序列”决定哪个是过载集的最佳可行函数。特别是,与此问题相关的是13.3.3.1(“隐式转换序列”),更具体地说,13.3.3.1.1(“标准转换序列”),它定义了这些转换序列的基本步骤。

13.3.3.1.1 / 1和表12将这些步骤分为四类,其中促销转换,以及基于个人类别的等级转换序列构成这些序列的转换。

在我们的案例中,我们有两个单一长度转换序列,由一个 Promotion 步骤组成(均由4.5./4允许)。

转换序列根据13.3.3.2排名。特别是,13.3.3.2 / 3提到转换序列S1优于转换序列S2,如果:

“等级 [即促销,转换等] 优于 S2的等级,或者S1和S2具有相同等级,可通过以下段落中的规则区分,或者,如果不是,[...]“

提到的“段落”是13.3.3.2/4,其中说:

“标准转换序列按其排名排序:完全匹配是一种比促销更好的转换,这是一种比转换更好的转换。具有相同排名的两个转换序列无法区分,除非一个适用以下规则:“

然后,接下来是一组在我们的情况下不适用的规则。

因此,我们有两个一步转换序列,由一个具有相同排名的 Promotion 组成。根据上述对当前标准的解释,呼叫必须含糊不清

但是,就个人而言,我同意需要进行更改,以便转换为无范围枚举的固定基础类型,而不是其他可能的转换。