Принудительное перечисление с беззнаковым длинным типом

Можно ли заставить базовый тип перечисления быть беззнаковым длинным типом? Благодаря

Ответы

Ответ 1

В С++ 03 нет способа заставить перечисленный тип иметь какую-либо конкретную базовую реализацию. Введите спецификацию С++ и раздел 7.2/5:

Основной тип перечисления является интегральным типом, который может представлять все значения перечисления, определенные в перечислении. Определяется реализация, тип интеграла используется как базовый тип для перечисления, за исключением того, что базовый тип не должен быть больше, чем int, если значение перечислителя не может быть помещено в int или unsigned int. Если список перечислений пуст, базовый тип выглядит так, как если бы перечисление имело один перечислитель со значением 0. Значение sizeof(), применяемое к типу перечисления, объекту типа перечисления или перечислителю, является значением sizeof() применяется к базовому типу.

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

Однако в С++ 0x они исправляют это, чтобы вы могли явно указать, какой тип вы хотите:

enum MyEnumeration: unsigned long {
   /* ... values go here ... */
};

Это позволит вам явно управлять базовым типом.

Ответ 2

Это может быть достигнуто в зависимости от вашего компилятора. Он не работает с Windows MSVS, но я тестировал его и работал со следующими версиями компилятора gcc/g++ (plus embedded cpp):

  • mipsel-openwrt-linux-uclibc-gcc.bin(OpenWrt/Linaro GCC 4.8-2014.04 r47072) 4.8.3
  • g++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) 5.4.0 20160609
  • gcc (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) 5.4.0 20160609
  • avr-g++. exe (AVR_8_bit_GNU_Toolchain_3.5.4_1709) 4.9.2

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

8
4
4

Источник:

#include <iostream>
using namespace std;

typedef enum
{
        ENUM_11,
        ENUM_12,

        enum1_force_long = 0x1122334455667788
} LongEnum1_t;

typedef enum
{
        ENUM_21,
        ENUM_22,

        enum2_force_long = 0x11223344
} LongEnum2_t;

typedef enum
{
        ENUM_31,
        ENUM_32,

        enum3_force_long = 0x1122
} LongEnum3_t;

LongEnum1_t enum1;
LongEnum2_t enum2;
LongEnum3_t enum3;
int main(void)
{
        cout << sizeof(enum1) << endl;
        cout << sizeof(enum2) << endl;
        cout << sizeof(enum3) << endl;

        return 0;
}

Ответ 3

Начиная с С++ 11 вы можете сделать enum MyEnum: unsigned long вот так:

enum Color : int { red, green, blue };
Color r = red;
switch(r)
{
    case red  : std::cout << "red\n";   break;
    case green: std::cout << "green\n"; break;
    case blue : std::cout << "blue\n";  break;
}

Ссылка: здесь