В настоящее время не существует полностью общего решения.Пункты представления перечисления, кажется, разработаны, чтобы затруднить получение этой информации.(Однако Ada 2020 добавит решение; подробности см. В нижней части этого ответа.)
Это:
function Rep is new Ada.Unchecked_Conversion(Enum, Integer);
, вероятно, сработает в большинстве случаев, но есть некоторые серьезные предостережения: значения представления должны находиться в диапазоне Integer'First..Integer'Last
, и если размеры Enum
и Integer
не совпадают, результат фактически определяется реализацией (но он работает с GNAT).
Как говорит Саймон Райт, RM рекомендует Unchecked_Conversion
, но это не очень удовлетворительное решение, и определить согласованный тип цели сложно.
Начиная с 2007 года RM рекомендуемый уровень поддержки:
Реализация должна поддерживать как минимум внутренние коды в диапазоне System.Min_Int..System.Max_Int.
, что означает, что преобразование в Integer
не всегда достаточно;значение может быть меньше Integer'First
или больше Integer'Last
.И даже если все значения находятся в этом диапазоне, нет действительно хорошего способа определить целевой тип, который имеет тот же размер, что и тип перечисления.Например, это:
type Enum is (Ten, Twenty, Thirty);
for Enum use (10, 20, 30);
function Rep is new Ada.Unchecked_Conversion(Enum, Integer);
выдает это предупреждение в GNAT:
warning: types for unchecked conversion have different sizes
Но после предупреждения Rep возвращает ожидаемые значения 10, 20 и 30.
RM явно заявляет, что если исходный и целевой размеры в экземпляре Unchecked_Conversion не совпадают, а тип результата скалярный, то
результат функции определяется реализацией,и может иметь недопустимое представление
Таким образом, тот факт, что вышеупомянутое работает для GNAT, не означает, что он гарантированно будет работать везде.
Для реализации, которая только поддерживает значения в диапазоне System.Min_Int..System.Max_Int
, вы можете сделать что-то вроде этого:
type Enum is (...);
for Enum use (...);
type Longest_Integer is range System.Min_Int .. System.Max_Int;
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Integer);
и игнорировать предупреждение.Но компиляторам разрешено принимать значения, превышающие System.Max_Int, если они находятся в диапазоне некоторого целочисленного типа.Например, GNAT отклоняет это, но другой компилятор Ada может принять это:
type Longest_Unsigned is mod System.Max_Binary_Modulus;
type Unsigned_Enum is (Zero, Huge);
for Unsigned_Enum use (0, Longest_Unsigned'Last);
и преобразование Unchecked_Conversion из этого в любой тип целого числа со знаком не будет работать.И у вас все еще есть потенциальная проблема реализации определенных результатов, если размеры не совпадают.
Вот общее решение, которое должно работать для любого типа перечисления , если (a) значения представленияв диапазоне System.Min_Int..System.Max_Int
, и (b) если реализация Unchecked_Conversion
ведет себя лучше, чем стандарт Ada требует, чтобы она была:
type Longest_Signed is range System.Min_Int .. System.Max_Int;
generic
type Enum is (<>);
function Generic_Rep(E: Enum) return Longest_Signed;
function Generic_Rep(E: Enum) return Longest_Signed is
function Rep is new Ada.Unchecked_Conversion(Enum, Longest_Signed);
begin
return Rep(E);
end Generic_Rep;
Учитывая все это заблуждение, вы можете рассмотреть возможность использования некоторого механизмакроме предложений представления перечисления, чтобы делать то, что вы пытаетесь сделать.
ОБНОВЛЕНИЕ:
GNAT имеет атрибуты, определенные реализацией 'Enum_Rep
и 'Enum_Val
.Ожидается, что Ada 2020 примет их.
http://www.ada -auth.org / standard / 2xrm / html / RM-13-4.html # p10.1