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

这解决了原始问题的“更多信息”部分,即需要使用包含作为实例化类型的子类型的参数的过程来实例化泛型。

本质上,使用泛型包来设置子类型,然后泛型子包提供所需的过程(使用泛型正式过程实例化)。诚然,这是一个相当复杂的问题解决方案。所以我们开始:

创建子类型的“父”泛型:

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 回答
3

您还可以将 with function "=" (Left : Index_Range_Type; Right : Count_Range_Type) Return boolean 放入泛型的标头中...强制用户提供适当的 equals 函数。

这条路线是必要的,因为就通用头文件现在而言,编译器可能不会假设这两种类型是相关的;从信息中没有给出的是签名。

于 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 回答
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_Type而不指定节中类型之间的关系generic。这样,您仍然可以使用您的子类型,但是任何Count_Range_Type不能强制转换为的通用过程实例Index_Range_Type都会引发异常。

我建议阅读Ada 95 Quality and Style Guide, 8.2.4了解更多关于使用泛型子类型的信息。

于 2012-07-05T09:14:36.280 回答