问题
This problem came up when answering this question about overload resolution with enums.
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);
}
Both MSVC2012NovCTP and gcc 4.7.1 agree on this output:
fct(char)
fct(int)
Shouldn't A
be converted from charEnum
to char
? Why is A
being converted to int
?
EDIT: 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.
Two relevant standard excerpts are §7.2/9:
The value of an enumerator or an object of an unscoped enumeration type is converted to an integer by integral promotion (4.5)
And §4.5/4:
A prvalue of an unscoped enumeration type whose underlying type is fixed (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 fixed can also be converted to a prvalue of the promoted underlying type.
So charEnum
can either be converted to char
, or any integral promotion of char
, such as 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.
回答1:
In C++03, the rule was:
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.
In a C++03 compiler, int
would be chosen because it is the first
on the list.
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.
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).
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.
Since it was reported as a defect in C++11, compilers should apply this fix when in C++11 mode and call fct(char)
.
回答2:
According to my interpretation of the current standard, the call has to be ambiguous. Follows an explanation.
Per 4.5/4:
"A prvalue of an unscoped enumeration type whose underlying type is fixed (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 fixed can also be converted to a prvalue of the promoted underlying type."
This offers two alternative promotions: a promotion to the underlying type, and a promotion to the promoted underlying type. Hence, this paragraph alone introduces ambiguity as for which of these alternatives should be used when resolving a function call to overloaded functions.
Then, paragraph 13.3.3 decides which is the best viable function of an overload set in terms of "conversion sequence". In particular, relevant for this matter is 13.3.3.1 ("Implicit conversion sequences") and, more specifically, 13.3.3.1.1 ("Standard conversion sequences"), which defines what elementary steps these conversion sequences are made of.
13.3.3.1.1/1 and Table 12 classify these steps into four categories, among which Promotion and Conversion, and rank conversion sequences based on the category of individual conversions that make up those sequences.
In our case, we have two one-length conversion sequences made up of a single Promotion step (both permitted by 4.5./4).
Conversion sequences are ranked according to 13.3.3.2. In particular, 13.3.3.2/3 mentions that a conversion sequence S1 is preferable to a conversion sequence S2 if:
"the rank [i.e. Promotion, Conversion, etc.] of S1 is better than the rank of S2, or S1 and S2 have the same rank and are distinguishable by the rules in the paragraph below, or, if not that, [...]"
The "paragraph below" being mentioned is 13.3.3.2/4, which says:
"Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:"
Then, what follows is a set of rules that do not apply in our situation.
Therefore, we have two one-step conversion sequences made up of a single Promotion with the same rank. According to the above interpretation of the current standard, the call has to be ambiguous.
Personally, however, I agree that a change is needed to make the conversion to the fixed underlying type of an unscoped enumeration preferable to other possible conversions.
来源:https://stackoverflow.com/questions/14206403/why-does-a-value-of-an-enum-with-a-fixed-underlying-type-of-char-resolve-to-fct