[英]How do I write the specification for a generic instantiation?
我将从Ada中通用过程的经典示例开始:
-------------------------
-- swaps.ads
-------------------------
package Swaps is
generic
type E is private;
procedure Generic_Swap (Left, Right : in out E);
end Swaps;
-------------------------
-- swaps.adb
-------------------------
package body Swaps is
procedure Generic_Swap (Left, Right : in out E) is
Temporary : E;
begin
Temporary := Left;
Left := Right;
Right := Temporary;
end Generic_Swap;
end Swaps;
现在,假设我想实现一个专门的String_Swap
过程来交换字符串,并将其提供给我的包的所有用户。 我可以在swaps.adb
的主体声明中添加以下swaps.adb
:
procedure String_Swap is new Generic_Swap (String);
但是,如果我在swaps.ads
未在规范中添加任何swaps.ads
,则没有软件包可以使用此过程。 例如:
-------------------------
-- main.adb
-------------------------
with Swaps; use Swaps;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
First : String := "world!";
Second : String := "Hello, ";
begin
String_Swap (First, Second); -- #Error: String_Swap is undefined#
Put_Line (First);
Put_Line (Second);
end Main;
我试图将过程的类型添加到规范中:
procedure String_Swap (Left, Right : in out String);
但随后Ada抱怨说此规范的正文缺失,并且swaps.adb
中的定义与此规范冲突。
我要解决的方法是使用子程序包:
with Ada.Strings.Unbounded;
package Swaps.Instances is
procedure Swap is new Generic_Swap (Element => Character);
procedure Swap is new Generic_Swap (Element => Ada.Strings.Unbounded.Unbounded_String;
...
end Swaps.Instances;
请注意,可以编写一个处理不确定类型的泛型:
generic
type Element (<>) is private;
并将Generic_Swap
的主体Generic_Swap
为
procedure Generic_Swap (Left, Right : in out Element) is
Temp : constant Element := Left;
begin -- Generic_Swap
Left := Right;
Right := Temp;
end Generic_Swap;
但要使用它,实际对象必须不受约束或具有相同的子类型。
Swaps
的用户唯一能看到的就是规格。 由于规范中与String_Swap
无关,因此包主体中的摆弄不会有任何不同。
如果要“实现用于交换字符串的专用String_Swap
过程”,则必须将其包括在规范中:
package Swaps is
generic
type E is private;
procedure Generic_Swap(Left, Right : in out E);
procedure String_Swap is new Generic_Swap(String);
end Swaps;
原来这是一个不好的例子:用-gnatl
编译时,我们得到
1. package Swaps is
2. generic
3. type E is private;
4. procedure Generic_Swap(Left, Right : in out E);
5. procedure String_Swap is new Generic_Swap(String);
|
>>> actual for "E" must be a definite subtype
6. end Swaps;
这是因为类型String
是不确定的,也就是,特定的String
具有特定的长度,并且只能分配到另一个String
(或切片String
)具有相同的长度; 因此,即使您的过程Main
在不使用泛型的情况下被写出,它也会在运行时因约束错误而失败。 在ARM A.4.5处查看Ada.Strings.Unbounded
。
因此,尝试使用确定的类型:
package Swaps is
generic
type E is private;
procedure Generic_Swap(Left, Right : in out E);
procedure Character_Swap is new Generic_Swap(Character);
end Swaps;
不幸,
1. package Swaps is
2. generic
3. type E is private;
4. procedure Generic_Swap(Left, Right : in out E);
5. procedure Character_Swap is new Generic_Swap(Character);
|
>>> warning: cannot instantiate "Generic_Swap" before body seen
>>> warning: Program_Error will be raised at run time
6. end Swaps;
解决方案必须分别实例化:也许在库级别,
with Swaps;
procedure Character_Swap is new Swaps.Generic_Swap(Character);
让用户根据需要实例化泛型将变得容易得多。
您不能将泛型用于String
类型,因为它是不受限制的类型。 但是让我们改用Ada.Strings.Unbounded.Unbounded_String
。
您要做的是:
with Ada.Strings.Unbounded;
package Swaps is
generic
type Element_Type is private;
procedure Generic_Swap (Left, Right : in out Element_Type);
procedure Swap (Left, Right : in out Ada.Strings.Unbounded.Unbounded_String);
end Swaps;
package body Swaps is
procedure Generic_Swap (Left, Right : in out Element_Type) is
Temporary : Element_Type;
begin
Temporary := Left;
Left := Right;
Right := Temporary;
end Generic_Swap;
procedure Swap_Unbounded_Strings is
new Generic_Swap (Element_Type => Ada.Strings.Unbounded.Unbounded_String);
procedure Swap (Left, Right : in out Ada.Strings.Unbounded.Unbounded_String) is
begin
Swap_Unbounded_Strings (Left => Left,
Right => Right);
end Swap;
end Swaps;
但是总的来说,我更喜欢将泛型的实例与这些泛型的规范和实现完全分开。
我试图将过程的类型添加到规范中:
procedure String_Swap (Left, Right : in out String);
但随后Ada抱怨说此规范的正文缺失,并且swaps.adb中的定义与此规范冲突。
这是个好主意,但是实例化无法完成过程声明(编译器会这样说)。 您需要使用一个过程重命名:
procedure String_Swap_Inst is new Generic_Swap (String);
procedure String_Swap (Left, Right : in out String)
renames String_Swap_Inst;
另外,为了能够将String与泛型一起使用,您需要对其进行一些更改以允许不受约束的类型:
package Swaps is
generic
type E (<>) is private;
procedure Generic_Swap (Left, Right : in out E);
procedure String_Swap (Left, Right : in out String);
end Swaps;
package body Swaps is
procedure Generic_Swap (Left, Right : in out E) is
Temporary : E := Left;
begin
Left := Right;
Right := Temporary;
end Generic_Swap;
procedure String_Swap_Inst is new Generic_Swap (String);
procedure String_Swap (Left, Right : in out String)
renames String_Swap_Inst;
end Swaps;
当然,您可以通过这种方式只交换长度相等的字符串,否则您将获得Constraint_Error,就像在分配中一样:
X : String (1 .. 2) := "123"; -- Constraint_Error!!!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.