I was playing with enums and tried to reproduce some examples from this page. Initial examples worked as intended, however I got some interesting results with following code:
#include <iostream>
enum num : char {
zero = '0',
one = '1',
two = '2',
three = '3',
four = '4',
five = '5',
six = '6'
};
int main()
{
const char two = '2';
std::cout << two << std::endl;
std::cout << num::two;
return 0;
}
The output is:
2
50
I expected both outcomes to be the same, but the num::two
seems to print some other value. Also this value doesn't changes(50)
, so I assume this isn't a random/garbage value & there is some sort of char/int parsing being done that I don't understand? Here is the ideone link.
I know that I can make it work by assigning like this zero = 0
, without single quotes and it works. However, I want to know what is happening behind the scenes and how could I control what non-single digits value I can print via single quotes assignments.
This should actually go to the char
overload now; unfortunately none of the compilers at issue implement DR 1601.
[conv.prom]/4:
A prvalue of an unscoped enumeration type whose underlying type is fixed ([dcl.enum]) can be converted to a prvalue of its underlying type.
This means num
can be promoted to char
.
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 num
can be promoted to int
, too.
The relevant candidates are:
template <class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
char ch );
template<class charT, class Traits>
basic_ostream<charT, Traits>& basic_ostream<charT, Traits>::operator<<(int);
For both candidates, the first argument is an identity conversion and the second is a promotion. Both num
to char
and num
to int
have promotion rank.
Pre-DR1601, these are equally as good, so the template/non-template tiebreaker comes in. The first one is a function template; the second one is a plain member function, so the second one wins.
DR1601 added a rule that says:
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.
This means that num
to char
is now better than num
to int
, so the first overload is now a better match and should be selected.
According to the C++ Standard (4.5 Integral promotions)
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 the integral promotion is applied and the operator << for objects of type int is called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With