5

我正在尝试编写一个通用包,所需的操作之一是校验和通过总线接收的数据记录。记录类型会有所不同,它是一个通用参数。但是,任何访问泛型参数成员的尝试都会导致编译错误。

错误......(Ada 95 GNAT 2009)

file.adb:XX no selector "Data" for private type "The_Transfer_Type" defined at file.ads:YY

宣言...

generic
  type The_Transfer_Type is private;
  SIZE : Integer;
package CC_Test_Channel is
  function Checksum(Msg : The_Transfer_Type) return Integer;
end package

还有身体...

function Checksum(Msg : The_Transfer_Type) return Integer is
  Sum : Integer := 0;
begin
  -- calculate the checksum
  for i in 1 .. SIZE loop
    Sum := Sum + Integer(Msg.Data(i));
  end loop;
  return Sum;
end Checksum;
4

3 回答 3

5

当您指定泛型参数是私有类型时,Ada 假设您是认真的 :-)

即你无权访问它的组件。Ada 不是“鸭子类型”,因此您是否知道实例化类型实际上可能拥有特定字段是无关紧要的。(如果 The_Transfer_Type 参数是用整数实例化的,您希望您的 Checksum 函数如何工作?)

解决此问题的一种方法是还提供一个访问器函数作为泛型的参数,该函数将检索所需的数据,在这种情况下,计算校验和。例如:

generic
   type The_Transfer_Type is private;
   with function Get_Checksummable_Data_Item
           (Msg : The_Transfer_Type;
            I   : Integer) return Integer;
   SIZE : Integer;

package CC_Test_Channel is
   function Checksum(Msg : The_Transfer_Type) return Integer;
end CC_Test_Channel;

那么身体是:

function Checksum(Msg : The_Transfer_Type) return Integer is
   Sum : Integer := 0;
begin
   -- calculate the checksum
   for i in 1 .. SIZE loop
      Sum := Sum + Get_Checksummable_Data(Msg, I);
   end loop;
   return Sum;
end Checksum;

然后,您为 Get_Checksummable_Data 提供的函数特定于 The_Transfer_Type,并简单地返回从 The_Transfer_Type 的组件字段中选择的值。

还有许多其他方法可以设置它,比如提供一个不受约束的数组类型作为通用形式参数和一个形式函数来检索它——这也允许您摆脱显式 SIZE 形式参数。或者您可以编写一个 Checksum() 函数作为对您正在实例化 CC_Test_Channel 的类型的操作之一,然后具有:

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

作为通用形式之一。

退后一步,想想可能性……

于 2010-02-26T13:39:55.253 回答
4

(从评论中移出,因为这很长)

Ada(95 及更高版本)支持流。与几乎用于字符串转换的 C++ 流不同,Ada 流旨在作为对数据执行操作(通常是 I/O)的通用机制。

每个 Ada 对象都有'Write'Read属性。有一些语言提供的流(用于文件 I/O),但您也可以通过从Ada.Streams.Root_Stream_Type派生来创建自己的流。如果您以这种方式编写自己的流,则有一些低级例程可以让您直接访问数据。

这允许您编写自己的流来执行诸如 I/O、数据压缩之类的操作,或者在您的情况下,可能会在将总线加载到变量之前对数据进行校验和(通过“读取”)。我过去曾亲自为我们的实时软件实现记录/播放功能。我也研究过一次压缩(我们最终不需要压缩)。

于 2010-03-01T14:34:37.337 回答
3
generic 
  type The_Transfer_Type is private; 
  ...

上面的代码意味着客户端可以提供他们为 The_Transfer_Type 设计的任何类型(只要它不是“受限的”)。这也意味着您的泛型对类型一无所知,除了分配可用。

对于 Ada 泛型,可以为泛型参数提供多少种不同类型的对象,以及对这些对象的泛型可用的操作之间存在某种反比关系。例如,最开放的类型是is limited private. 您可以为其中一个提供任何类型的东西。然而,泛型对它几乎无能为力。甚至分配都不可用。

去掉“有限”,你可以用它做分配,但只能提供可以分配的类型。在另一个极端,您可以将其定义为: type The_Transfer_Type is (<>)然后您可以提供任何整数或枚举类型,并获得类似'first. 更进一步,您可以这样做type The_Transfer_Type is range <>,并且您将获得进行整数数学运算的能力,但只能提供整数数字类型。

于 2010-02-26T20:18:22.967 回答