[英]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.