Что делает enum - ›int лучшим преобразованием, чем enum -› unsigned?

В следующем коде вместо f(unsigned) выбрана перегрузка f(int). Протестировано с помощью clang 3.0 и gcc 4.8.

enum E
{
};

E f(int);
int f(unsigned);

E e = f(E(0));

Мое чтение стандарта привело меня к мысли, что enum -> int и enum -> unsigned являются идентичными стандартными последовательностями преобразования, которые содержат только интегральное преобразование.

[conv.integral] r-значение перечислимого типа может быть преобразовано в r-значение целочисленного типа.

Согласно [over.best.ics], ранг стандартной последовательности преобразования, содержащей только целое преобразование, - «Преобразование».

[over.ics.rank] Две неявные последовательности преобразования одной и той же формы являются неотличимыми последовательностями преобразования, если не применяется одно из следующих правил: [...]

Кажется, что ни одно из упомянутых правил не применимо при сравнении двух стандартных последовательностей преобразования.

Что мне не хватает?


person willj    schedule 23.07.2013    source источник
comment
enum по умолчанию имеет базовый int, поэтому я подозреваю, что это преобразование лучше. Если вы скажете ему использовать short или char, готов поспорить, вы получите ожидаемую двусмысленность.   -  person Mooing Duck    schedule 23.07.2013
comment
Вы должны использовать std::underlying_type, чтобы определить базовый тип перечисления.   -  person Kerrek SB    schedule 23.07.2013
comment
Комплексное продвижение. На самом деле это не интегральное преобразование; см. [conv.prom]   -  person dyp    schedule 23.07.2013
comment
enumerations (7.2) are not integral; however, enumerations can be promoted to int, unsigned int, long, or unsigned long, as specified in 4.5. .. но C ++ 03 4.5 не упоминает перечисления!   -  person willj    schedule 23.07.2013
comment
по крайней мере, когда я читал это не в первый раз;)   -  person willj    schedule 23.07.2013
comment
Помните, что перечисления могут быть как отрицательными, так и положительными; enum {Val1 = -1};, поэтому преобразование в int более естественно.   -  person Steztric    schedule 24.07.2013
comment
@Steztric: Близко, но это неправда. Каждый enum является отдельным типом, и правила преобразования различаются enum в зависимости от диапазона. Поскольку исходный пример enum E не имеет отрицательных чисел, он подчиняется другим правилам, чем ваш пример.   -  person MSalters    schedule 24.07.2013


Ответы (1)


C++11:

[conv.prom] / 3

Prvalue типа перечисления с незаданной областью, базовый тип которого не фиксирован (7.2), может быть преобразован в prvalue первого из следующих типов, который может представлять все значения перечисления (т. Е. Значения в диапазоне от b min до b max, как описано в 7.2): int, unsigned int, long int, unsigned long int, long long int или unsigned long long int.

(курсив мой)

Затем [over.ics.rank] / 4:

Стандартные последовательности конверсии упорядочены по их рангу: точное совпадение - лучшая конверсия, чем продвижение, а это лучшая конверсия, чем конверсия.

Таким образом, для разрешения перегрузки в выражении f(E(0)) перегрузка E f(int); требует только интегрального продвижения (с E на int, через [conv.prom]), которое имеет более высокий ранг интегрального преобразования, необходимого для int f(unsigned);E на unsigned через [ усл. интеграл]).


Для C ++ 03 аргументация такая же, хотя первая цитата немного отличается: [conv.prom] / 2

Rvalue типа wchar_t (3.9.1) или типа перечисления (7.2) может быть преобразовано в rvalue первого из следующих типов, которые могут представлять все значения его базового типа: int, unsigned int, long или unsigned long.

[over.ics.rank] / 4 то же самое.

person dyp    schedule 23.07.2013
comment
@willj Насколько мне известно, интегральное продвижение не является широко известной функцией. - person dyp; 23.07.2013
comment
@willj Это также немного противоречит интуиции, например char будет преобразовывать скорее в int, чем в unsigned char (или short) для разрешения перегрузки, для того же резонанса. - person dyp; 23.07.2013