2

这真是一个烦人的问题。我有一个包含各种基本类型的记录类型,现在我需要它能够自己存储一个向量(来自 Ada.Containers.Vectors !我想这是不可能的,但谁能给我关于如何以另一种方式解决这个问题的建议?为了让您更好地了解我在做什么,以下是不起作用的:

with Base_Types; use Base_Types;
with Ada.Strings.Wide_Unbounded; use Ada.Strings.Wide_Unbounded;
with Ada.Containers.Vectors;
with Green_Tasks; use Green_Tasks;
with Ada.Unchecked_Deallocation;

package Boxed_Types is

   type String_Ptr is access Unbounded_Wide_String;
   procedure Free_Unbounded_Wide_String is new Ada.Unchecked_Deallocation
     (Object => Unbounded_Wide_String, Name => String_Ptr);
   type Vector_Ptr; -- this won't work

   type Type_T is (T_Null, T_UInt64, T_Text, T_Bool, T_GTask, T_Vector);
   type Item (IType : Type_T := T_Null) is record
      case IType is
         when T_Null   => null;
         when T_UInt64 => UInt64      : UInteger_64;
         when T_Text   => String      : String_Ptr;
         when T_Bool   => Bool        : Boolean;
         when T_GTask  => Green_Task  : Green_Task_Ptr;
         when T_Vector => Item_Vector : Vector_Ptr;     -- error here 
      end case;
   end record;

   package Item_Vectors is new Ada.Containers.Vectors
     (Index_Type   => Natural,
      Element_Type => Item);
   use Item_Vectors;
   type Vector_Ptr is access Vector;
end Boxed_Types;

这给了我一个不那么意外的错误“在完全声明之前类型的无效使用”对于 Vector_Ptr。但是,我也不能在声明 Item 之前实例化向量包,我确实需要将向量和基本类型包装到一个记录类型中。(这是我在业余时间写的解释器;VM 必须在堆栈上存储各种不同的类型,存储在异构数组中,操作它们等等。)

我是否必须完全打破类型安全并弄乱地址才能访问转换,还是有更清洁的解决方案?

4

3 回答 3

2

这是一个不同的版本,它将项目(而不是其访问权限)存储在 Vector 中。它通过使用继承来工作,创建一个基本类型的 Vector。这意味着 Indefinite_Vector 因为每个单独组件的大小事先不知道。

同样,已编译但未经测试。

with Ada.Containers.Indefinite_Vectors;

package Boxed_Base is

   type Base_Item is tagged record
      null;
   end record;

   package Item_Vectors is new Ada.Containers.Indefinite_Vectors
     (Index_Type   => Natural,
      Element_Type => Base_Item'Class);
   use Item_Vectors;

   type Vector_Ptr is access Vector;

end Boxed_Base;

此基本类型具有可以存储在向量中的属性,并且其存储管理由 Indefinite_Vectors 处理。现在我们可以继承它,具有我们需要的特性。

with Ada.Strings.Wide_Unbounded; use Ada.Strings.Wide_Unbounded;
with Ada.Unchecked_Deallocation;
with Boxed_Base;

package Boxed_Types is

   type UInteger_64 is new integer;
   type Green_Task_Ptr is access UInteger_64;
   -- these two because original testcase was incomplete

   type String_Ptr is access Unbounded_Wide_String;
   type Type_T is (T_Null, T_UInt64, T_Text, T_Bool, T_GTask, T_Vector);

   type Item (IType : Type_T ) is new Boxed_Base.Base_Item with record
      case IType is
         when T_Null   => null;
         when T_UInt64 => UInt64      : UInteger_64;
         when T_Text   => String      : String_Ptr;
         when T_Bool   => Bool        : Boolean;
         when T_GTask  => Green_Task  : Green_Task_Ptr;
         when T_Vector => Item_Vector : Boxed_Base.Vector_Ptr;    
      end case;
   end record;

end Boxed_Types;

原始设计的一个功能已经消失:标记类型不允许使用默认判别式:这意味着您创建一个具有明确判别式(因此具有确定大小!)的实例并且以后不能修改它(只需将对象替换为新的一个)。

另一个特性可能值得一提:Indefinite_Vectors 可能对其 Definite 表亲有性能损失:如果是这样,那是异构对象大小所产生的必要成本,并且会以某种形式弹出,但是您可以解决问题。

也可以通过为每种类型的 Item 创建不同的子类来消除判别式 Type_T;也许是一个更简洁的设计,但在这个阶段,重构比你可能想要的更多!

于 2013-05-19T19:44:11.417 回答
1

我清理了一下,下面的编译(如果你用 null 替换 green-tasks;我没有 Green_Tasks 包),但我没有测试它。

with
Interfaces,
Green_Tasks,
Ada.Containers.Indefinite_Vectors,
Ada.Strings.Wide_Unbounded;

use
Green_Tasks,
Ada.Strings.Wide_Unbounded;

package Boxed_Types is

    type Type_T is (T_Null, T_UInt64, T_Text, T_Bool, T_GTask, T_Vector);
    type Item (IType : Type_T := T_Null) is private; -- Forward declaration;    


private

    type NNA_Item is Not Null Access Item;

    package Item_Vectors is new Ada.Containers.Indefinite_Vectors
      ( Index_Type   => Natural,
        Element_Type => NNA_Item
      );    

    type Item (IType : Type_T := T_Null) is record
        case IType is
        when T_Null   => null;
        when T_UInt64 => UInt64      : Interfaces.Unsigned_64;
        when T_Text   => String      : Unbounded_Wide_String;
        when T_Bool   => Bool        : Boolean;
        when T_GTask  => Green_Task  : Green_Task_Ptr;
        when T_Vector => Item_Vector : Item_Vectors.Vector;
        end case;
    end record;

end Boxed_Types;
于 2013-05-19T19:26:49.970 回答
0

我怀疑 Shark8 有您正在寻找的答案。布赖恩·德拉蒙德刚刚发布了一个与我类似的选项!

但是,作为一种完全不同的方法,您可以尝试(未编译,类似 ada 的伪代码):

文件 Boxed_Types.ads:

type item is tagged null record;

type item_ptr is access all item'Class;

package Item_Vectors is new Ada.Containers.Vectors
  ( Index_Type   => Natural,
    Element_Type => item_ptr -- Actually you may have to wrap this in a record type and possibly make it a controlled type.
  );    

procedure foo (object : in item'Class) is abstract;

文件:boxed_types.uint64.adb(或选择您自己的合理名称):

type T_uint64 is new item with record
  UInt64      : Interfaces.Unsigned_64;
end record;

procedure foo (object : in T_uint64);

对原始记录中的其他元素重复此操作。

这意味着您可以声明类范围的对象并使用动态调度:

declare
   Obj : Boxed_Types.Item'Class := ...; 
begin
   Boxed_Types.foo; -- dynamic dispatching
end;

这应该可以解决 Item 包含 Item 的问题,并且具有在对其数据字段进行操作之前不必询问类型的进一步优势!

于 2013-05-19T20:07:20.623 回答