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

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

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

 #include  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 ?

EDIT: clang жалуется, что вызов неоднозначен, что согласуется с моей интерпретацией ниже; что, я бы все же нашел его гораздо более интуитивным, если бы он считался только базовым типом.


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

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

И §4.5 / 4:

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

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

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

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

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

    Значение типа неперечисленного enums (7.2 [dcl.enum]) может быть преобразовано в rvalue первого из следующих типов, которые могут представлять все значения enums (т.е. значения в диапазоне 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. Интегральное продвижение enums игнорирует фиксированный базовый тип , эта формулировка была изменена на абзац, который вы указали в п. 4.5 / 4, и, прочитав отчет о дефекте, кажется, что целью комитета было fct(char) ( базовый тип).

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

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

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

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

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

    По 4,5 / 4:

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

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

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

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

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

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

    «ранг [т.е. продвижение, преобразование и т. д.] из S1 лучше, чем ранг S2, или S1 и S2 имеют одинаковый ранг и различимы по правилам в параграфе ниже , или, если не это, [.. .]»

    Приведенный ниже « абзац » – это 13.3.3.2/4, в котором говорится:

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

    Далее следует следующее множество правил, которые не применимы в нашей ситуации.

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

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