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

Базовый тип слабо типизированного перечисления в С++ 11

В С++ 11 введены строго типизированные перечисления с синтаксисом enum class. Они несовместимы с целыми типами и требуют явного приведения для получения их числового значения. С++ 11 также вводит возможность указать класс хранения для слабо типизированных перечислений с формой enum name : type {}. Здесь все хорошо.

Но похоже, что даже если слабо типизированное перечисление имеет заданный класс хранения, тип его элементов по-прежнему int. Я попытался с выпуском Visual Studio 2012, ноябрь CTP. Рассмотрим следующий код:

enum charEnum : char { A = 'A' };
enum longEnum : long long { Tera = 1000000000000 };

void fct(char val) {}
void fct(int val) {}
void fct(long long val) {}

int main() 
{
    static_assert(sizeof(A) == sizeof(char), "check charEnum size");
    static_assert(sizeof(Tera) == sizeof(long long), "check longEnum size");
    fct('A');  // calls fct(char)
    fct(1);    // calls fct(int)
    fct(2ll);  // calls fct(long long)
    fct(A);    // calls fct(int) !
    fct(Tera); // calls fct(int), with truncation !
    fct((long long)Tera);  // calls fct(long long)
    return 0;
}

Перегруженная функция, называемая значением перечисления, всегда fct(int), даже если это приводит к усечению значения. Конечно, при явном приведении мы можем вызвать перегруженную функцию, но это также возможно в традиционном синтаксисе С++ 03.

Я пропустил что-то очевидное? Почему это? Есть ли лучшее обходное решение, чем явный листинг?

4b9b3361

Ответ 1

Это ошибка компилятора. Согласно §7.2/9 и §4.5/4:

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

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

Последний должен преобразовать в long long, а не int. Дело char - это точка зрения. (!)


Программа тестирования:

#include <iostream>

enum charEnum : char      { A = 'A' };
enum longEnum : long long { Tera = 1000000000000 };

void fct(char val)      { std::cout << "fct(char)"      << std::endl; }
void fct(int val)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long val) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    static_assert(sizeof(A)    == sizeof(char),      "check charEnum size");
    static_assert(sizeof(Tera) == sizeof(long long), "check longEnum size");

    fct('A');
    fct(1);
    fct(2ll);
    fct(A);
    fct(Tera);
    fct((long long)Tera);
}

Выход MSVC2012NovCTP:

ГЦТ (char)
ГЦТ (INT)
fct (длинный)
ГЦТ (INT)
ГЦТ (INT)
fct (длинный длинный)

g++ 4.7.1:

ГЦТ (char)
ГЦТ (INT)
fct (длинный)
ГЦТ (INT)
fct (длинный)
fct (длинный длинный)