Почему значение перечисления с фиксированным базовым типом char разрешается в fct (int) вместо fct (char)?

Эта проблема возникла при ответе этот вопрос о разрешении перегрузки с перечислениями.

Пока дело за long long определенно была ошибка в MSVC2012NovCTP (согласно стандартному тексту и тесту с gcc 4.7.1), я не могу понять, почему происходит следующее поведение:

#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);
}

И MSVC2012NovCTP, и gcc 4.7.1 согласны с этим выводом:

ПКТ (символ)
ГЦТ (целое)

не должны A быть преобразованным из charEnum в char? Почему A превращается в int?

РЕДАКТИРОВАТЬ: Clang жалуется, что вызов является неоднозначным, что согласуется с моим толкованием ниже; Тем не менее, я все равно нашел бы это гораздо более интуитивно понятным, если бы он считался только базовым типом.


Два соответствующих стандартных выдержки — §7.2 / 9:

Значение перечислителя или объекта типа перечисления с незаданной областью преобразуется в целое число путем интегрального преобразования (4.5)

И §4.5 / 4:

Значение типа перечисления с незаданной областью, базовый тип которого фиксирован (7.2), может быть преобразовано в значение базового типа. Кроме того, если интегральное продвижение может быть применено к его базовому типу, prvalue типа перечисления с незаданной областью, базовый тип которого фиксирован, также может быть преобразовано в prvalue повышенного базового типа.

Так charEnum может быть преобразован в charили любое интегральное продвижение char, такие как int,

Но для меня это расплывчато, потому что «может» не совсем говорит, что на самом деле будет выбрано. Во всяком случае, это должно быть двусмысленным с этой формулировкой, потому что между char или любое из его акций. Если вы закомментируете fct(int)тогда звонок является неоднозначный. Почему int специальный?

Единственное, о чем я могу думать, это то, что интегральные продвижения применяются рекурсивно, но ничего, что я вижу, не требует этого.

24

Решение

В C ++ 03 правило было таким:

Значение типа перечисления с незаданной областью (7.2 [dcl.enum]) может быть
преобразуется в значение первого из следующих типов, которые могут
представляют все значения перечисления (то есть значения в
диапазон от bmin до bmax, как описано в 7.2 [dcl.enum]): int, unsigned int,
long int, unsigned long int, long long int или unsigned long long int.

В компиляторе C ++ 03 int будет выбран, потому что это первый
в списке.


В C ++ 11 базовый тип был представлен. Соответственно, через 685. Интегральное продвижение перечисления игнорирует фиксированный базовый тип , эта формулировка была изменена на параграф, который вы цитировали в §4.5 / 4, и после прочтения отчета о дефекте, похоже, что намерение комитета было fct(char) (базовый тип), который будет выбран.

Однако, согласно обсуждению под основной вопрос 1601, текст в C ++ 11 на самом деле делает преобразование неоднозначным (fct(char) а также fct(int) оба возможны, и ни один не является предпочтительным).

Следующее исправление было предложено и принято в C ++ 14:

Преобразование, которое продвигает перечисление, базовый тип которого
фиксированный к его базовому типу лучше, чем тот, который способствует
повышен базовый тип, если они разные.

Поскольку в C ++ 11 это было сообщено как дефект, компиляторы должны применить это исправление в режиме C ++ 11 и вызвать fct(char),

9

Другие решения

Согласно моей интерпретации текущего стандарта, вызов должен быть неоднозначным. Следует объяснение.

По 4.5 / 4:

«Значение типа перечисления с незаданной областью, базовый тип которого является фиксированным (7.2), может быть преобразовано в значение базового типа. Кроме того, если интегральное продвижение может быть применено к базовому типу, значение перечисления с незаданной областью, базовый тип которого исправлено также может быть преобразовано в prvalue повышенного базового типа. «

Это предлагает две альтернативы промо акции: повышение до основного типа и повышение до способствовало базовый тип. Следовательно, только этот параграф вносит двусмысленность в отношении который из этих альтернатив следует использовать при разрешении вызова функции для перегруженных функций.

Затем в параграфе 13.3.3 решается, какая из функций перегрузки, заданных с точки зрения «последовательность преобразования». В частности, актуальным для этого вопроса является 13.3.3.1 («Последовательности неявного преобразования«) и, более конкретно, 13.3.3.1.1 («Стандартные последовательности преобразования«), который определяет, из каких элементарных шагов сделаны эти последовательности преобразования.

13.3.3.1.1 / 1 и таблица 12 классифицируют эти этапы на четыре категории, среди которых Продвижение а также преобразование, и ранговые последовательности преобразования, основанные на категории отдельных преобразований, которые составляют эти последовательности.

В нашем случае мы имеем две последовательности преобразования одной длины, составленные из одного Продвижение шаг (оба допускаются по 4.5./4).

Последовательности конверсии ранжируются согласно 13.3.3.2. В частности, 13.3.3.2/3 упоминает, что последовательность преобразования S1 предпочтительнее последовательности преобразования S2, если:

«ранг [Т.е. Продвижение, конверсия и т. Д.] из S1 является лучше, чем звание S2 или S1 и S2 имеют того же ранга и различаются по правилам в пункте ниже, или, если не это, […] «

«абзац ниже«упомянуто 13.3.3.2/4, в котором говорится:

«Стандартные последовательности конвертации упорядочены по их рангу: точное совпадение — это лучшая конверсия, чем рекламная акция, которая является лучшей конверсией, чем конверсия. Две последовательности преобразования с одинаковым рангом неразличимы, если не применяется одно из следующих правил

Затем следует набор правил, которые не применяются в нашей ситуации.

Таким образом, у нас есть две одношаговые последовательности преобразования, состоящие из одного Продвижение с таким же рангом. Согласно приведенной выше интерпретации действующего стандарта, вызов должен быть неоднозначным.

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

3

По вопросам рекламы [email protected]