为什么具有固定基础类型 char 的枚举值解析为 fct(int) 而不是 fct(char)?
这个问题是在回答这个关于枚举重载解析的问题时出现的.
虽然long long
的情况肯定是MSVC2012NovCTP中的一个错误(根据标准文本和gcc 4.7.1的测试),但我无法弄清楚为什么会出现以下行为:>
While the case for long long
was definitely a bug in MSVC2012NovCTP (according to the standard text and a test with gcc 4.7.1), I cannot figure out why the following behavior occurs:
#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 都同意这个输出:
Both MSVC2012NovCTP and gcc 4.7.1 agree on this output:
fct(字符)
fct(int)
fct(char)
fct(int)
A
不应该从 charEnum
转换成 char
吗?为什么将 A
转换为 int
?
Shouldn't A
be converted from charEnum
to char
? Why is A
being converted to int
?
clang 抱怨调用不明确,这与我下面的解释一致;也就是说,如果仅将其视为基础类型,我仍然会发现它更直观.
clang complains that the call is ambiguous, which agrees with my interpretation below; that said, I would still find it much more intuitive if it were only considered to be the underlying type.
两个相关的标准摘录是 §7.2/9:
Two relevant standard excerpts are §7.2/9:
通过整数提升(4.5)将枚举器或无作用域枚举类型的对象的值转换为整数
The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion (4.5)
和第 4.5/4 节:
And §4.5/4:
基础类型是固定的 (7.2) 的无作用域枚举类型的纯右值可以转换为其基础类型的纯右值.此外,如果可以对其基础类型应用整型提升,则其基础类型是固定的无作用域枚举类型的纯右值也可以转换为提升的基础类型的纯右值.
A prvalue of an unscoped enumeration type whose underlying type is ?xed (7.2) can be converted to a prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a prvalue of an unscoped enumeration type whose underlying type is ?xed can also be converted to a prvalue of the promoted underlying type.
所以charEnum
既可以转换为char
,也可以是char
的任何整数提升,例如int
.
So charEnum
can either be converted to char
, or any integral promotion of char
, such as int
.
但这对我来说很模糊,因为可以"并不能完全说明实际会选择哪个.如果有的话,这应该与此措辞含糊不清,因为在 char
或其任何促销之间没有优先考虑.如果您注释掉 fct(int)
,则调用 不明确.为什么 int
很特别?
But this is vague to me because "can" doesn't quite say which will actually be chosen. If anything, this should be ambiguous with this wording because no preference is given between char
or any of its promotions. If you comment out fct(int)
, then the call is ambiguous. Why is int
special?
我唯一能想到的就是递归应用积分提升,但我没有看到任何强制要求.
The only thing I can think of is that integral promotions are applied recursively, but nothing I see mandates it.
推荐答案
在 C++03 中,规则是:
In C++03, the rule was:
无作用域枚举类型 (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.
An rvalue of an unscoped enumeration type (7.2 [dcl.enum]) can be converted to an rvalue of the first of the following types that can represent all the values of the enumeration (i.e. the values in the range bmin to bmax as described in 7.2 [dcl.enum]): int, unsigned int, long int, unsigned long int, long long int, or unsigned long long int.
在 C++03 编译器中,将选择 int
因为它是第一个在名单上.
In a C++03 compiler, int
would be chosen because it is the first
on the list.
在 C++11 中,引入了底层类型.因此,通过 685.枚举的整体提升忽略了固定的底层类型,这个措辞改为你在§4.5/4中引用的段落,从阅读缺陷报告来看,委员会的意图似乎是为了fct(char)
(底层类型)被选择.
In C++11, the underlying type was introduced. Accordingly, via 685. Integral promotion of enumeration ignores fixed underlying type , this wording was changed to the paragraph you quoted in §4.5/4 and from reading the defect report, it seems the intention of the committee was for fct(char)
(the underlying type) to be chosen.
但是,根据核心问题1601下的讨论,C++11 中的文本实际上使转换变得模棱两可(fct(char)
和 fct(int)
都是可能的,但都不是首选).
However, according to the discussion under core issue 1601, the text in C++11 actually makes the conversion ambiguous (fct(char)
and fct(int)
are both possible and neither is preferred).
以下修复被提出并被 C++14 接受:
The following fix was proposed and accepted into C++14:
促进枚举的转换,其基础类型为固定到其底层类型比提升到提升的基础类型,如果两者不同.
A conversion that promotes an enumeration whose underlying type is fixed to its underlying type is better than one that promotes to the promoted underlying type, if the two are different.
由于它被报告为 C++11 中的缺陷,因此编译器应在 C++11 模式下应用此修复程序并调用 fct(char)
.
Since it was reported as a defect in C++11, compilers should apply this fix when in C++11 mode and call fct(char)
.
相关文章