泛型参数的声明并不足以提供类型关系(子类型),而且这些信息只是丢失了......例如:
-- 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绝对通用且独立。
答案 0 :(得分: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采用的方法,其中泛型用“基础”类型实例化,然后泛型提供“增强” - 在该包中它是一种访问类型,在此将是子类型。
答案 1 :(得分:3)
您还可以使用函数“=”(左:Index_Range_Type;右:Count_Range_Type)将布尔值返回到通用标题...强制用户提供适当的等于函数。
需要该路由,因为现在通用标头,编译器可能不会假设他有两种类型相关;签名没有提供信息。
答案 2 :(得分: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;
答案 3 :(得分: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以获取有关使用泛型的子类型的更多信息。