Эта проблема возникла при ответе этот вопрос о разрешении перегрузки с перечислениями.
Пока дело за 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
специальный?
Единственное, о чем я могу думать, это то, что интегральные продвижения применяются рекурсивно, но ничего, что я вижу, не требует этого.
В 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)
,
Согласно моей интерпретации текущего стандарта, вызов должен быть неоднозначным. Следует объяснение.
По 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, в котором говорится:
«Стандартные последовательности конвертации упорядочены по их рангу: точное совпадение — это лучшая конверсия, чем рекламная акция, которая является лучшей конверсией, чем конверсия. Две последовательности преобразования с одинаковым рангом неразличимы, если не применяется одно из следующих правил:»
Затем следует набор правил, которые не применяются в нашей ситуации.
Таким образом, у нас есть две одношаговые последовательности преобразования, состоящие из одного Продвижение с таким же рангом. Согласно приведенной выше интерпретации действующего стандарта, вызов должен быть неоднозначным.
Однако лично я согласен с тем, что для того, чтобы преобразование в фиксированный базовый тип перечисления с незаданной областью было предпочтительнее других возможных преобразований, необходимо внести изменения.