Подтвердить что ты не робот

Почему значение перечисления с фиксированным базовым типом 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 специальный?

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

4b9b3361

Ответ 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, в котором говорится:

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

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

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

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