获取Ada中枚举类型的表示值

use*_*854 11 enumeration ada

我需要在Ada中获取与枚举类型的值相关联的数值.不是枚举中的位置,而是使用"for TYPE use"子句为每个值赋值的值.

有谁知道这是否可能?

Kei*_*son 12

目前还没有完全通用的解决方案.枚举表示条款似乎旨在使这些信息难以获得.(但Ada 2020将添加解决方案;有关详细信息,请参阅此答案的底部.)

这个:

function Rep is new Ada.Unchecked_Conversion(Enum, Integer);
Run Code Online (Sandbox Code Playgroud)

在大多数情况下可能会起作用,但有一些严重的警告:表示值必须在范围内Integer'First..Integer'Last,如果结果的大小EnumInteger结果不匹配实际上是实现定义的(但它适用于GNAT).

正如Simon Wright所说,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);
Run Code Online (Sandbox Code Playgroud)

在GNAT中生成此警告:

warning: types for unchecked conversion have different sizes
Run Code Online (Sandbox Code Playgroud)

但在警告之后,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);
Run Code Online (Sandbox Code Playgroud)

并忽略警告.但是允许编译器接受大于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);
Run Code Online (Sandbox Code Playgroud)

并且从此到任何有符号整数类型的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;
Run Code Online (Sandbox Code Playgroud)

鉴于所有这些混淆,您可以考虑使用除枚举表示子句之外的某种机制来执行您尝试执行的任何操作.

更新:

GNAT具有实现定义的属性'Enum_Rep'Enum_Val.预计Ada 2020将采用它们.

http://www.ada-auth.org/standards/2xrm/html/RM-13-4.html#p10.1


Mar*_*c C 6

如果您正在使用GNAT,并且不介意特定于编译器,则该编译器为此提供Enum_Rep属性.