如何在泛型中声明对任何子程序形式类型的访问?

How to declare access to any subprogram formal type in generic?

我需要做一个泛型包,其形参应该是子程序的访问类型。这种类型的对象被传递给这个包的子例程,我必须检查它是否相等。

generic
   type Func_Type is private; 
package Gen_Package is
   function Check(Func : Func_Type) return Boolean is
     (Func = null);
end;

但这无法编译,因为比较中的左操作数没有访问类型。

您可以利用访问类型对象的初始值为null:

这一事实
generic
   type Func_Type is private;
   --  make comparison operator available. `is <>` means it does not
   --  need to be given explicitly if it is visible at the site of instantiation.
   with function "=" (Left, Right : Func_Type) return Boolean is <>;
package Gen_Package is
   function Check (Func : Func_Type) return Boolean;
end Gen_Package;

package body Gen_Package is
   function Check (Func : Func_Type) return Boolean is
      --  not constant because we cannot give an initialization expression.
      --  if Func_Type is an access type, Null_Value will be initialized with null.
      Null_Value : Func_Type;
   begin
      return Func = Null_Value;
   end Check;
end Gen_Package;

您应该指定您需要的子程序访问类型作为您的形式参数。 Ada 语言参考手册第 12.5.4 节指出:“对于正式访问子程序子类型,正式和实际的指定配置文件应符合子类型。

这导致声明如下:

generic
   type func_type is access function(S : String) return string;
   gen_func : not null func_type;
   type proc_type is access procedure (Msg : in String);
   gen_proc : not null proc_type;
package test_subprog is
   procedure Print;
end test_subprog;

必须同时声明访问子程序类型和相应访问子程序实例的形参。如果指定形式参数必须为“非空”,则无需在代码中测试空参数。

with Ada.Text_IO; use Ada.Text_IO;

package body test_subprog is

   -----------
   -- Print --
   -----------

   procedure Print is
      Msg : string := "This is a test";
   begin
      Put_Line(Item => gen_func(Msg));
      gen_proc(gen_func(Msg));
   end Print;

end test_subprog;

调用作为通用参数传递的子程序的正式访问不需要特殊语法。制作实际参数的实例以使用通用包可以这样做:

with Ada.text_io; use Ada.Text_IO;
with test_subprog;

procedure Main is
   function format(S : String) return String is
   begin
      return "Called through function access " & S;
   end format;
   
   type format_access is access function(S : string) return String;
   
   procedure reformat(S : String) is
   begin
      Put_Line("Called through procedure access " & S);
   end reformat;
   
   type proc_access is access procedure (S : String);
   
   package sub_test is new test_subprog(func_type => format_access,
                                        gen_func  => format'access,
                                        proc_type => proc_access,
                                        gen_proc  => reformat'access);
begin
   sub_test.print;
end Main;

这种复杂的方法允许您使用对子程序类型的访问作为通用参数。除非您确实需要访问子程序类型,否则可以简单地使用子程序形式参数,如 Ada 语言参考手册第 12.6 节所述:

通用正式子程序示例:

with function "+"(X, Y : Item) return Item is <>;
with function Image(X : Enum) return String is Enum'Image;
with procedure Update is Default_Update;
with procedure Pre_Action(X : in Item) is null;  -- defaults to no action
with procedure Write(S    : not null access Root_Stream_Type'Class;
                     Desc : Descriptor)
                     is abstract Descriptor'Write;  -- see 13.13.2
-- Dispatching operation on Descriptor with default
--  given the generic procedure declaration 
generic
   with procedure Action (X : in Item);
procedure Iterate(Seq : in Item_Sequence);
--  and the procedure 
procedure Put_Item(X : in Item);
--  the following instantiation is possible 
procedure Put_List is new Iterate(Action => Put_Item);

In generic packet will also be passed a function that accepts this type.

也许像

generic -- GP
   type Func_Ptr (<>) is limited private; -- Expected to be an access type

   with function Is_Null (Ptr : in Func_Ptr) return Boolean;

   with procedure Use_It (Ptr : in Func_Ptr);
package GP is
   procedure Checked_Use (Ptr : in Func_Ptr);
end GP;

package body GP is
   procedure Checked_Use (Ptr : in Func_Ptr) is
      -- Nothing here
   begin -- Checked_Use
      if not Is_Null (Ptr) then
         Use_It (Ptr => Ptr);
      else
         -- Handle null ptr
      end if;
   end Checked_Use;
end GP;

?

如果没有关于您的意图的更多信息,很难提供帮助。通常,当您发现自己与类型系统作对时,这表明您存在设计问题。