Ambiguous overload when writing an enum with an enum-base, but only with clang

左心房为你撑大大i 提交于 2019-12-01 20:36:43

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!