具有持续访问父类型对象的 Ada 记录

Ada record with constant access-to-object-of-parent-type

我最近开始学习 Ada。我想看看是否有可能在 Ada 中创建一个 Boost::Statechart-like 框架。为此,我需要一个具有常量访问父类型组件对象的记录结构,例如静态指向另一个树节点的树节点,并且 父指针不得在所有时间。像这样:

-- Not working sample

type Node_T is record
    Parent : constant access Node_T;
    -- error: constant components are not permitted
end record;
-- I wish to create objects of this type like this

Top_Node : Node_T (null);
Child1_Node : Node_T (Top_Node'Access);
Child2_Node : Node_T (Top_Node'Access);

Ada 似乎不支持常量成员字段。所以我求助于使用访问鉴别器:

-- Not working sample

type Node_T (Parent : access Node_T) is null record;
-- error: type declaration cannot refer to itself

但是,使用命名访问类型作为判别有效

type Node_T;
type Ref_Node_T is access all Node_T;

type Node_T (Parent : Ref_Node_T) is null record;

但是,据我了解,这会导致 Node_T 对象的生命周期绑定到 Ref_Node_T 对象的生命周期,而不是另一个父 Node_T 对象的生命周期。这是真的吗?

有没有更好的方法来实现我的需要?

https://www.sigada.org/ada_letters/june2000/sanden.pdf 中描述了另一种创建有限状态机的方法 此解决方案使用受保护对象和任务的组合来实现有限状态机。

FSM 的另一种替代解决方案是使用枚举和数组,如果您需要多个,generic

Generic
   Type State is (<>); -- Any discrete type.
   Type Event is (<>);
Package Finite_State_Machine_Domain is
   Type Domain is Array(State, Event) of State;
   
   Generic
     Start,
     Error : State;
   Package Finite_State_Machine is
      Type State_Machine is private;
      Function  Create    (State_Map : Domain)            return State_Machine;
      Function  Get_State (Object : in     State_Machine) return State;
      Procedure Send_Event(Object : in out State_Machine; Transition : in Event);
   Private
      Type State_Machine is record
         Current   : State  := Start;
         State_Map : Domain := (Others => Error);
      End record;
   End Finite_State_Machine;
End Finite_State_Machine_Domain;

Package Body Finite_State_Machine_Domain is
   Package Body Finite_State_Machine is

      Function  Create (State_Map : Domain) return State_Machine is
       ( State_Machine'(State_Map => State_Map, Others => <>) );

      Function  Get_State (Object : in     State_Machine) return State is
       ( Object.Current );

      Procedure Send_Event(Object : in out State_Machine; Transition : in Event) is
      Begin
         if Object.Current /= Error then
            Object.Current:= Object.State_Map(Object.Current, Transition);
         end if;
      End Send_Event;

   End Finite_State_Machine;
End Finite_State_Machine_Domain;