问题
I would like to use operator<< to write an enum with a specified base type. To my surprise, it seems I must write out the operator myself. For example, the code I would like to write is
#include <iostream>
enum myenum : uint16_t
{
X = 0,
};
int main ()
{
std::cout << "Value is" << X << std::endl;
return 0;
}
gcc 4.8 and visual studio 2015 have no problems with this. clang++-3.6 errors with
# clang++-3.6 -std=c++11 -O0 ostream.cpp -o test.exe
ostream.cpp:18:29: error: use of overloaded operator '<<' is ambiguous (with operand types
'basic_ostream<char, std::char_traits<char> >' and 'myenum')
std::cout << "Value is" << X << std::endl;
~~~~~~~~~~~~~~~~~~~~~~~ ^ ~
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:181:7: note:
candidate function
operator<<(unsigned short __n)
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/ostream:189:7: note:
candidate function
operator<<(int __n);
^
... another 14 candidates along the same lines ...
In general, I'm inclined to believe clang when it comes to strict conformance, so maybe the use really is ambiguous. The enum certainly is convertible to other sorts of integers. I hoped that the compiler would prefer the version corresponding to the base type of the enum.
I can work around by using some other language feature instead of enum ... : uint16_t or by explicitly typing out the operator in which case clang is also content.
static inline std::ostream & operator<<(std::ostream & out, myenum const & s)
{
out << static_cast<std::underlying_type<myenum>::type> (s);
return out;
}
This looks absurd though. Is clang's behaviour expected or erroneous?
回答1:
Clang problem. Minimized repro:
enum myenum : unsigned short
{
X = 0,
};
void f(unsigned short);
void f(int);
int main ()
{
f(X);
return 0;
}
[conv.prom]/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.
[over.ics.rank]/4.2 - this bullet was added by CWG1601 as a DR against C++11:
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:
- [...]
- 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.
myenum
->unsigned short
and myenum
->int
have the same rank (Promotion). Per [over.ics.rank]/4.2, the first is better than the second. There's no ambiguity here.
OTOH, GCC silently calls the wrong overload (the int
one), which isn't that much better.
来源:https://stackoverflow.com/questions/34336024/ambiguous-overload-when-writing-an-enum-with-an-enum-base-but-only-with-clang