3

ジェネリックパラメーターの宣言は、型の関係(サブタイプ)を与えるのに十分なほど網羅的ではなく、この情報は単に失われます...例:

-- generic_p.ads
generic
   type Index_Range_Type is range <>;
   type Count_Range_Type is range <>;
procedure Generic_P (I : Index_Range_Type, C : Count_Range_Type);

-- generic_p.adb
procedure Generic_P (I : Index_Range_Type, C : Count_Range_Type) is
begin
   if I = C then -- oops : cannot compare different types...
     -- ...
   end if;
end Generic_P;

-- main.adb
procedure Main is
   type Index_Range_Type is 0 .. 512;
   subtype Count_Range_Type is Index_Range_Type range 1 .. Index_Range_Type'Last;

   procedure P is new Generic_P (Index_Range_Type, Count_Range_Type);

   I : Index_Range_Type := 33;
   C : Count_Range_Type := 42;
begin
   if I = C then -- Ok : Count_Range is a subset of Index_Range, they can be compared
      -- ...
   end if;
   P (I, C);
end Main;

これにより、generic_p.adbでの比較に対して次のエラーが発生します:invalid operand types [...] left operand has type "Index_Range_Type" [...] right operand has "type Count_Range_Type"。サブタイピングは、一般的な手順では表示されません。

ジェネリックパラメーター間の関係を指定する方法はありますか?

詳細情報

Count_Range_Typeプロシージャのパラメータとして、を必要とする別のパラメータを追加できるようにする必要がありますCount_Range_Type

-- generic_p.ads
generic
   type Index_Range_Type is range <>;
   type Count_Range_Type is range <>;
   with procedure F (C : Count_Range_Type);
procedure Generic_P (I : Index_Range_Type, C : Count_Range_Type);

タイプを直接使用することはできません。Pは完全に汎用的で独立している必要があります。

4

4 に答える 4

3

with関数"="(左:Index_Range_Type;右:Count_Range_Type)をジェネリックのヘッダーに返すこともできます...これにより、ユーザーは適切なequals関数を提供するように強制されます。

汎用ヘッダーが現在使用されているため、コンパイラーは2つのタイプが関連していると想定しない可能性があるため、このルートが必要です。情報から与えられていないのは署名です。

于 2012-07-05T02:43:56.923 に答える
3

私の頭のてっぺんから、おそらくあなたのニーズを満たすかもしれないものを誰が宣言するかを逆にします。ジェネリックにサブタイプを定義させることを検討してください。

generic
   type Index_Range_Type is range <>;
package Generic_Provider is

   pragma Assert(Index_Range_Type'First = 0);
   subtype Count_Range_Type is Index_Range_Type range 1 .. Index_Range_Type'last;

   procedure P (I : Index_Range_Type; C : Count_Range_Type);

end Generic_Provider;

体内:

package body Generic_Provider is

   procedure P (I : Index_Range_Type; C : Count_Range_Type) is
   begin
      if I = C then -- No problem comparing now...
            -- ...
         null;
      end if;
   end P;
end Generic_Provider;

次に、インスタンス化ユニットで:

with Generic_Provider;

procedure Main is
   type Index_Range_Type is range 0 .. 512;
   package P_Provider is new Generic_Provider (Index_Range_Type);

   subtype Count_Range_Type is P_provider.Count_Range_Type;


   I : Index_Range_Type := 33;
   C : Count_Range_Type := 42;
begin
   if I = C then -- Ok : Count_Range is a subset of Index_Range, and all is good.
         -- ...
      null;
   end if;
   P_Provider.P (I, C);
end Main;

これは、 System.Address_To_Access_Conversionsが採用するアプローチに似ています。これにより、ジェネリックは「ファウンデーション」タイプでインスタンス化され、ジェネリックは「拡張機能」を提供します。このパッケージでは、アクセスタイプであり、この場合はサブタイプになります。

于 2012-07-04T16:36:23.793 に答える
3

これは、元の質問の「詳細情報」の部分に対処します。これにより、インスタンス化タイプのサブタイプであるパラメーターを含むプロシージャを使用して、ジェネリックをインスタンス化する必要があります。

基本的に、ジェネリックパッケージを使用してサブタイプを設定し、ジェネリック子パッケージが目的のプロシージャを提供します(ジェネリック正式プロシージャでインスタンス化されます)。確かに、これは問題に対するかなり複雑な解決策です。だからここに行きます:

サブタイプを作成する「親」ジェネリック:

generic
   type Index_Range_Type is range <>;
package Generic_Provider is
   pragma Assert(Index_Range_Type'First = 0);
   subtype Count_Range_Type is Index_Range_Type range 1 .. Index_Range_Type'last;

end Generic_Provider;

これはサブタイプを宣言するだけで、本文は必要ありません(実際、本文は違法になります)。

これは、クライアント提供の正式なプロシージャを利用するプロシージャプロバイダーの仕様です。

generic
   with procedure F(I : Index_Range_Type;
                    C : Count_Range_Type);

package Generic_Provider.Services is

   procedure P (I : Index_Range_Type; C : Count_Range_Type);

end Generic_Provider.Services;

ニヤリと言うだけで、その本体は、正式なプロシージャを呼び出すことができ、サブタイプの比較が有効であることを確認します。

package body Generic_Provider.Services is

   procedure P (I : Index_Range_Type; C : Count_Range_Type) is
   begin
      if I = C then
         F(I, C);
      end if;
   end P;

end Generic_Provider.Services;

最後に、インスタンス化するメインプログラム:

with Generic_Provider.Services;

procedure Main is
   type Index_Range_Type is range 0 .. 512;
   package Type_Provider is new Generic_Provider (Index_Range_Type);
   subtype Count_Range_Type is Type_Provider.Count_Range_Type;

   procedure My_F (I : Index_Range_Type;
                   C : Count_Range_Type) is
   begin
      null;
   end My_F;

   package P_Provider is new Type_Provider.Services(My_F);

   I : Index_Range_Type := 33;
   C : Count_Range_Type := 42;
begin
   if I = C then
      null;
   end if;
   P_Provider.P (I, C);
end Main;
于 2012-07-05T13:50:29.603 に答える
2

サブタイプの代わりにフルタイプを使用できます。

-- generic_p.ads
generic
   type Index_Range_Type is range <>;
   type Count_Range_Type is new Index_Range_Type;
procedure Generic_P (I : Index_Range_Type; C : Count_Range_Type);

-- generic_p.adb
procedure Generic_P (I : Index_Range_Type; C : Count_Range_Type) is
begin
   -- Neccessary conversion
   if I = Index_Range_Type (C) then
     -- ...
   end if;
end Generic_P;

-- main.adb
procedure Main is
   type Index_Range_Type is 0 .. 512;
   type Count_Range_Type is new Index_Range_Type range 1 .. Index_Range_Type'Last;

   procedure P is new Generic_P (Index_Range_Type, Count_Range_Type);

   I : Index_Range_Type := 33;
   C : Count_Range_Type := 42;
begin
   if I = Index_Range_Type (C) then
      -- ...
   end if;
   P (I, C);
end Main;

セクション内のタイプ間の関係を指定せずに、にキャストCすることもできます。そうすれば、サブタイプを引き続き使用できますが、にキャストできない汎用プロシージャのインスタンスは例外を発生させます。Index_Range_TypegenericCount_Range_TypeIndex_Range_Type

ジェネリックスでのサブタイプの使用の詳細については、Ada 95品質およびスタイルガイド、8.2.4を読むことをお勧めします。

于 2012-07-05T09:14:36.280 に答える