如何将枚举转换为整数以处理 overflow/wraparound?

How do I cast an enum to an Integer to handle overflow/wraparound?

我正在学习 ada,我正在尝试为枚举实现加法重载。

基本上我希望能够将一个整数添加到 Day 类型并获得生成的 Day 值。所以星期一 + 2 => 星期三。

这是我的简化代码:

procedure overload is                                                                                                             
    type Day is (                                                                                                                 
        Sunday,                                                                                                                   
        Monday,                                                                                                                   
        Tuesday,                                                                                                                  
        Wednesday,                                                                                                                
        Thursday,                                                                                                                 
        Friday,                                                                                                                   
        Saturday                                                                                                                  
    );
    day1 : Day := Monday;
    function "+" (left: Day; right: Integer) return Day is                                                                        
        -- how would I handle this here? I want to basically say
        -- if Day + Integer > Saturday then
        --   wraparound back to Sunday
        return DayValue;
    begin
       for x in 0 .. 7 loop
          Ada.text_io.put_line("Monday + " & Integer'Image(x) & " = " & Day'Image(day1 + x));
       end loop;
end overload;

您可以使用'Pos 和'Val 属性来完成。 'Pos returns 提供的日期相对于第一个选项(索引为 0)的位置,而 'Val 采用 Pos 值和 returns 日期类型值:

return Day'Val(Day'Pos(Left) + Right);

对于环绕检查星期六的'Pos 值与左+右值的'Pos 值并使用星期日的Day'Val(0)

或者将您的 Right 输入类型从 Integer 切换为 Natural 并使用模数数学:

return Day'Val((Day'Pos(left) + Right) mod 7);

你甚至可以花点心思,为 7 设置一个常量:

Day_Mod : constant := Day'Pos(Day'Last) - Day'Pos(Day'First) + 1;

然后变成

return Day'Val((Day'Pos(left) + Right) mod Day_Mod);

虽然您有一个获取与枚举值关联的位置值的答案,但不要认为这与 C 中的枚举相同。Ada 枚举不是数字类型。

您可以使用 for 循环遍历一系列枚举值,如

for the_day in Day loop in loop
   Put_Line(Day'Image(the_day));
end loop;

如果要打印当天和第二天可以使用'Succ属性。

for the_day in Day loop
   Put(Day'Image(the_day) & " the next day is ");
   if the_day = Day'Last then
      Put_Line(Day'Image(Day'First));
   else
      Put_Line(Day'Image(the_day'Succ));
   end if;
end loop;

我会使用 PragmARC.Wrapping:

with PragmARC.Wrapping;

function "+" (Left : Day; Right : Integer) return Day is
   package Wrapping is new PragmARC.Wrapping (Item => Day);
   use Wrapping;

   Result : Day := Left;
begin -- "+"
   Change : for I in 1 .. abs Right loop
      Result := (if Right < 0 then Wrap_Pred (Result) else Wrap_Succ (Result) );
   end loop Change;

   return Result;
end "+";