Generics 泛型信息丢失';参数

Generics 泛型信息丢失';参数,generics,ada,Generics,Ada,泛型参数的声明不够详尽,无法给出类型关系(子类型),这些信息只是丢失了。。。例如: -- 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 G

泛型参数的声明不够详尽,无法给出类型关系(子类型),这些信息只是丢失了。。。例如:

-- 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;

我不能直接使用这个类型,我需要p是绝对通用的和独立的。

在我的脑海里,也许颠倒了谁声明了什么可以满足你的需要。考虑具有泛型定义的子类型:

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;
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;
然后在实例化单元中:

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;

这类似于所采取的方法,即泛型被实例化为“基本”类型,然后泛型提供“增强”——在该包中它是一个访问类型,在该包中它将是子类型。

您还可以放置一个with函数“=”(左:索引范围类型;右:计数范围类型)将布尔值返回到泛型的标题中。。。这迫使用户提供适当的equals函数


这条路径是必需的,因为由于泛型头现在已经存在,编译器可能不会假设这两种类型是相关的;信息中没有给出的是签名。

您可以使用完整类型而不是子类型:

-- 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;
——通用广告
通用的
类型索引\范围\类型为范围;
类型计数\范围\类型是新的索引\范围\类型;
程序泛型(I:索引范围类型;C:计数范围类型);
--通用的
程序泛型(I:索引范围类型;C:计数范围类型)为
开始
--必要的转换
如果I=索引\范围\类型(C),则
-- ...
如果结束;
结束泛型(P);
--main.adb
主要程序是
类型索引\范围\类型为0。。512;
类型计数\范围\类型是新索引\范围\类型范围1。。索引\范围\类型'Last;
程序P是新的泛型P(索引范围类型、计数范围类型);
I:指数范围类型:=33;
C:计数范围类型:=42;
开始
如果I=索引\范围\类型(C),则
-- ...
如果结束;
P(I,C);
端干管;
也可以将
C
强制转换为
索引范围类型
,而无需在
通用
部分中指定类型之间的关系。这样,您仍然可以使用子类型,但是任何
Count\u Range\u Type
不能强制转换为
Index\u Range\u Type
的泛型过程实例都会引发异常

我建议阅读,以了解有关将子类型与泛型一起使用的更多信息。

这解决了原始问题的“进一步信息”部分,其中泛型需要使用包含作为实例化类型的子类型的参数的过程进行实例化

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

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

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;
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;
仅针对grins,其主体验证是否可以调用正式过程以及子类型比较是否有效:

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;

这就是我使用的解决方案,直到我需要一个新参数:一个以Index\u Range\u Type作为参数类型的函数。看看我的最后一个例子。发布了一个新的答案,直接解决了这个问题。我总是尽量避免使用强制转换,但这是目前最简单的解决方案。。。我想知道这是语言设计的限制还是遗漏。正确。我不是这个解决方案的忠实粉丝,但至少我们避免了强制转换,并保持了软件的完整性。谢谢你的帮助:)
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;