generics - 包含对基于该记录的通用包实例化的访问的记录

标签 generics containers record ada forward-declaration

这确实是一个令人烦恼的问题。我有一个包含各种基本类型的记录类型,现在我需要它能够存储一个向量(来自 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 之前我也无法实例化向量包,而且我确实需要将向量和基本类型包装到一个记录类型中。 (这是我在业余时间写的解释器;虚拟机必须在堆栈上、异构数组中存储各种不同的类型,操作它们等等......)

我是否必须完全破坏类型安全并弄乱地址才能访问转换,或者是否有更干净的解决方案?

最佳答案

这是一个不同的版本,它将项目(而不是其访问权限)存储在向量中。它通过使用继承来工作,创建基本类型的 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;也许是一个更简洁的设计,但在这个阶段,重构比您可能想要的更多!

关于generics - 包含对基于该记录的通用包实例化的访问的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16638137/

相关文章:

clojure - 命名空间限定记录字段访问器

haskell - 如何简洁地修改记录的字段?

arrays - 采用泛型数组的 Swift 函数

video - DirectShow - 它是什么?

java - 为什么Java声称1.5版本需要向后兼容?

c++ - 在 C++ 中将函数作为参数传递给模板?

linux - 在容器内重启 Apache2 时出错

haskell - "Modern"HList?

c# - 反射(reflect)类型的默认值(T)

generics - 我可以在没有未经检查的异常的情况下使用 Collections.EMPTYLIST 吗?