5

汎用パッケージを作成しようとしていますが、必要な操作の1つは、バスを介して受信したデータレコードをチェックサムすることです。レコードタイプはさまざまであり、一般的なパラメータです。ただし、ジェネリックパラメータのメンバーにアクセスしようとすると、コンパイルエラーが発生します。

エラー...(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パラメーターが整数でインスタンス化された場合、チェックサム関数がどのように機能することを期待しますか?)

これに対処する1つの方法は、この場合はチェックサムを計算するために必要なデータを取得するジェネリックへのパラメーターとしてアクセサー関数も提供することです。例えば:

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仮パラメーターを削除することもできます。または、CC_Test_Channelをインスタンス化するタイプの操作の1つとしてChecksum()関数を記述し、次のようにすることもできます。

with function Calculate_Checksum(Msg : The_Transfer_Type) return Integer;

一般的な形式の1つとして。

一歩下がって、可能性について考えてください...

于 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。それらの1つに任意のタイプのwhatsoverを提供できます。ただし、ジェネリックはそれでほとんど何もできません。割り当てさえ利用できません。

「制限付き」を取り除いて、それを使って割り当てを行うことができますが、割り当てることができるタイプのみを提供できます。もう一方の極端な例では、次のように定義できます。 type The_Transfer_Type is (<>)次に、任意の整数型または列挙型を指定すると、のようなものが得られ'firstます。さらに進んで、あなたはできるでしょうtype The_Transfer_Type is range <>、そしてあなたは整数の数学演算をする能力を得るでしょう、しかしあなたは整数の数値型を供給することしかできないでしょう。

于 2010-02-26T20:18:22.967 に答える