Почему значение перечисления с фиксированным базовым типом 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 соглашаются на этом выходе:
ГЦТ (char)
fct (int)
Не следует ли A
преобразовать из charEnum
в char
? Почему A
преобразуется в int
?
EDIT: clang жалуется, что вызов неоднозначен, что согласуется с моей интерпретацией ниже; что, я бы все же нашел его гораздо более интуитивным, если бы он считался только базовым типом.
Двумя соответствующими стандартными выдержками являются §7.2/9:
Значение перечислителя или объекта неперечисленного типа перечисления преобразуется в целое число путем цельной рассылки (4.5)
И §4.5/4:
Значение незанятого типа перечисления, базовый тип которого фиксируется (7.2), может быть преобразовано в prvalue его базового типа. Более того, если интегральное продвижение может быть применено к его базовому типу, то prvalue неперечисленного типа перечисления, базовый тип которого фиксируется, также может быть преобразовано в prvalue продвинутого базового типа.
Итак, charEnum
может быть преобразовано в char
или любое целое продвижение char
, например int
.
Но это расплывчато для меня, потому что "может" не совсем сказать, что на самом деле будет выбрано. Во всяком случае, это должно быть двусмысленным с этой формулировкой, потому что нет никакого предпочтения между char
или любым из его рекламных акций. Если вы закомментируете fct(int)
, вызов будет неоднозначным. Почему int
специальный?
Единственное, о чем я могу думать, это то, что интегральные поощрения применяются рекурсивно, но я ничего не вижу в нем.
Ответы
Ответ 1
В С++ 03 это правило было:
Значение типа неперечисленного перечисления (7.2 [dcl.enum]) может быть преобразуется в rvalue первого из следующих типов, которые могут представляют все значения перечисления (т.е. значения в диапазон bmin до bmax, как описано в 7.2 [dcl.enum]): int, unsigned int, long int, unsigned long int, long long int или unsigned long long int.
В компиляторе С++ 03 int
будет выбрано, потому что это первый
в списке.
В С++ 11 был введен базовый тип. Соответственно, через 685. Интегральное продвижение перечисления игнорирует фиксированный базовый тип, эта формулировка была изменена на абзац, который вы указали в п. 4.5/4, и, прочитав отчет о дефекте, кажется, что целью комитета было fct(char)
(базовый тип).
Однако, согласно обсуждению в основной проблеме 1601, текст на С++ 11 делает преобразование неоднозначным (fct(char)
и fct(int)
возможны и не являются предпочтительными).
В С++ 14 было предложено и принято следующее исправление:
Преобразование, которое способствует перечислению, базовый тип которого привязанный к его базовому типу, лучше, чем тот, который способствующий базовому типу, если они отличаются друг от друга.
Поскольку он был указан как дефект в С++ 11, компиляторы должны применять это исправление в режиме С++ 11 и вызывать fct(char)
.
Ответ 2
В соответствии с моей интерпретацией текущего стандарта вызов должен быть неоднозначным. Следующее объяснение.
Per 4.5/4:
"Значение типа неперечисленного перечисления, базовый тип которого является фиксированным (7.2), может быть преобразован в prvalue его базового типа. Кроме того, если интегральное продвижение может быть применено к его базовому типу, prvalue неперечисленного типа перечисления чей базовый тип фиксирован, также может быть преобразован в prvalue продвинутого базового типа."
Это предлагает две альтернативные акции: продвижение по базовому типу и продвижение по продвинутому базовому типу. Следовательно, только этот абзац вводит двусмысленность в отношении того, какой из этих альтернатив следует использовать при разрешении вызова функции перегруженным функциям.
Затем в пункте 13.3.3 решается, что является наилучшей жизнеспособной функцией набора перегрузки в терминах "последовательности преобразования. В частности, актуальным для этого является 13.3.3.1 (" Неявные последовательности преобразования ") и, более конкретно, 13.3.3.1.1 (" Стандартные последовательности преобразования"), который определяет, какие элементарные этапы выполняют эти последовательности преобразования.
13.3.3.1.1/1 и таблица 12 классифицируют эти этапы на четыре категории, среди которых: Продвижение и Преобразование, а также последовательности преобразования рангов на основе категории отдельных преобразований, составляющих эти последовательности.
В нашем случае мы имеем две одномерные последовательности преобразования, состоящие из одного шага Promotion (оба разрешены 4.5./4).
Последовательности конверсии оцениваются согласно 13.3.3.2. В частности, в 13.3.3.2/3 упоминается, что последовательность S1 преобразования предпочтительна для последовательности преобразования S2, если:
"ранг [т.е. продвижение, преобразование и т.д.] из S1 лучше ранга S2, или S1 и S2 имеют того же ранга и различаются по правилам в абзац ниже, или, если не тот, [...]"
Приведенный ниже "абзац" - это 13.3.3.2/4, в котором говорится:
"Стандартные последовательности преобразования упорядочены по их рангу: точное соответствие - лучшее преобразование, чем продвижение, которое является лучшим преобразованием, чем преобразование. Две последовательности преобразований с одинаковым рангом неразличимы, если только одно из следующих правила применяются:"
Далее следует, что набор правил, которые не применяются в нашей ситуации.
Следовательно, у нас есть две одношаговые последовательности преобразования, состоящие из одной Акции с тем же рангом. Согласно приведенной выше интерпретации текущего стандарта вызов должен быть неоднозначным.
Однако я согласен с тем, что необходимо внести изменения, чтобы преобразование в фиксированный базовый тип не облажаемой нумерации предпочтительнее других возможных преобразований.