It doesn't seem like this is possible, but I haven't seen a definitive answer. What I want to do is define a generic subprogram with some generic formal parameters and instantiate it in the same package, like the following simplified and untested example:
generic
Proc_Address : access System.Address;
type Param_1_Type (<>) is private;
procedure Procedure_IP(Param_1 : Param_1_Type);
Instance_1_Address : System.Address := ...
procedure Instance_1 is new Procedure_IP(Instance_1_Address, type_1);
Instance_2_Address : System.Address := ...
procedure Instance_2 is new Procedure_IP(Instance_2_Address, type_2);
--etc
But this kind of thing keeps resulting in those "access before elaboration" errors. I can't seem to find any pragmas that will affect elaboration of a single subprogram; seems it has to be the whole package. Attempts to move the generic subprogram into a separate package have proven more troublesome than I had hoped because the specific stuff I want the function to do is closely related to other things happening in the same package.
Is there any way to resolve the elaboration order issue, so that I can keep the declaration and instantiations in the same package?
Option B is to rework this in a different way, like maybe passing a function pointer to a non-generic function or something, but doing it as a generic seems to be the cleanest way to go about it, especially since I'll need to refer to each of the intended instances a lot.
So the package or subprogram body must be complete before you can instantiate a generic. That said, you can use a package hierarchy to address the issue of needing to share data between the main package and the procedure if in a different file. Ada provides "private" child packages that can be shared among its siblings. You essentially do a hierarchy like this:
Top_Level | ---------------------------------------------------------------- | | | Top_Level.Main_Package Top_Level.Generic_Procedure Top_Level.Private_Package
Then both Main_Package and Generic_Procedure have access to things in Private_Package and you can instantiate Generic_Procedure in Main_Package. Example Code to follow is below. Notice how both Main_Package and Generic_Procedure can access Thing in Private_Package and since the package is private, only they can use it.
top_level.ads
package Top_Level with Pure is end Top_Level;
top_level-main_package.ads
with Top_Level.Generic_Procedure;
with System;
private with Top_Level.Private_Package;
package Top_Level.Main_Package is
subtype type_1 is Integer;
subtype type_2 is String;
Instance_1_Address : System.Address := System.Null_Address;
procedure Instance_1 is new Generic_Procedure(Instance_1_Address, type_1);
Instance_2_Address : System.Address := System.Null_Address;
procedure Instance_2 is new Generic_Procedure(Instance_1_Address, type_2);
function Get_Thing return Integer;
private
function Get_Thing return Integer is (Private_Package.Thing);
end Top_Level.Main_Package;
top_level-generic_procedure.ads
with System;
generic
Proc_Address : System.Address;
type Param_1_Type (<>) is private;
procedure Top_Level.Generic_Procedure(Param_1 : Param_1_Type);
top_level-generic_procedure.adb
with Top_Level.Private_Package;
with Ada.Text_IO;
procedure Top_Level.Generic_Procedure
(Param_1 : Param_1_Type)
is
begin
Ada.Text_IO.Put_Line(Private_Package.Thing'Image);
end Top_Level.Generic_Procedure;
top_level-private_package.ads
private package Top_Level.Private_Package is
Thing : constant Integer := 3;
end Top_Level.Private_Package;
Full compiled example on godbolt: https://godbolt.org/z/7qaaPc4Ex