Generics 带有默认子程序的Ada通用包

Generics 带有默认子程序的Ada通用包,generics,ada,Generics,Ada,我正在尝试创建一个Ada通用包,它有一个带有默认值的子程序参数。我无法让编译器识别默认值。。我猜这是因为能见度。是否有方法在泛型声明中向前声明函数 通用规范: generic type Item is private; type Item_Ref is access all Item; Addr : System.Address; Default : Item; with Is_Valid (Obj : Item) return Boolean;

我正在尝试创建一个Ada通用包,它有一个带有默认值的子程序参数。我无法让编译器识别默认值。。我猜这是因为能见度。是否有方法在泛型声明中向前声明函数

通用规范:

generic
    type Item is private;
    type Item_Ref is access all Item;
    Addr : System.Address;
    Default : Item;

    with Is_Valid (Obj : Item) return Boolean;

    -- Forward Declare ** DOES NOT COMPILE
    function Default_Validate (Data_Ptr : Item_Ref) return Boolean;

    with function Validate (Data_Ptr : Item_Ref) return Boolean is Default_Validate;

package Foo is

    -- function Default_Validate (Data_Ptr : Item_Ref) return Boolean;

    function Read_Eeprom return Item;

end Foo;
一般机构:

package body Foo is

    Obj : aliased Item;
    for Obj'Address use Addr;

    -- Read Method
    function Read_Eeprom return Item is
    begin

        -- ** Read EEPROM using OBJ **

        Validate (Obj'Unchecked_Access);

    end Read_Eeprom;

    -- Default Validate Method
    function Default_Validate (Data_Ptr : Item_Ref) return Boolean is 
        Valid : Boolean;
    begin
        Valid := Is_Valid(Data_Ptr.all);

        if not Valid then
            Data_Ptr.all := Default;
        end if;

        return Valid;
    end Default_Validate;

end Foo;
司机

with Foo;
procedure Main is
    MAX_INT : constant Integer := 100;
    MIN_INT : constant Integer := 0;

    -- Special / Non-Scaler Type
    type Pair_Type is 
        record
            X : Integer;
            Y : Integer;
        end record;

    type Pair_Ref is access all Pair;

    -- Is Valid
    function Int_Is_Valid(Int : Integer) return Boolean is
    begin 
        return (Int <= MAX_INT and Int >= MIN_INT);
    end Pair_Is_Valid;

    -- Is Valid
    function Pair_Is_Valid(Pair : Pair_Type) return Boolean is
    begin 
        return Pair.X'Valid and Pair.Y'Valid;
    end Pair_Is_Valid;

    -- Validate
    function Pair_Validate(Pair : Pair_Ref) return Boolean is
        Valid : Boolean := True;
    begin
        if not Pair.X'Valid then
            Pair.X := 0;
            Valid := False;
        end if;

        if not Pair.Y'Valid then
            Pair.Y := 0;
            Valid := False;
        end if;

        return Valid;
    end Special_Validate;

    type Int_Ref is access all Integer;

    My_Int  : Integer;
    My_Pair : Pair_Type;
    Default_Pair : Pair_Type := (0,0);

    package Int_Obj is new Foo (Item => Integer,
                                Item_Ref => Int_Ref,
                                Addr => My_Int'Address,
                                Default => 0,
                                Is_Valid => Int_Is_Valid);

    package Pair_Obj is new Foo (Item => Pair_Type,
                                 Item_Ref => Pair_Ref,
                                 Addr => My_Pair'Address,
                                 Default => Default_Pair,
                                 Is_Valid => Pair_Is_Valid,
                                 Validate => Pair_Validate);

   Tmp_Int   : Integer;
   Tmps_Pair : Pair_Type;

begin

   Tmp_Int := Int_Obj.Read_Eeprom;
   Tmp_Pair := Pair_Obj.Read_Eeprom;

end Main;
与Foo;
主要程序是
最大整数:常数整数:=100;
最小整数:常数整数:=0;
--特殊/非定标器类型
类型对\u类型为
记录
X:整数;
Y:整数;
结束记录;
类型Pair_Ref是访问所有Pair;
--有效
函数Int_是有效的(Int:Integer)返回布尔值为
开始
返回值(Int=MIN_Int);
端对_有效;
--有效
函数对\u有效(对:对类型)返回布尔值为
开始
返回Pair.X'Valid和Pair.Y'Valid;
端对_有效;
--证实
函数对验证(对:对引用)返回布尔值为
有效:布尔值:=True;
开始
如果不是成对的,那么X'有效
对X:=0;
有效:=假;
如果结束;
如果不是成对的,那么你是有效的
Y:=0;
有效:=假;
如果结束;
返回有效;
结束特殊验证;
Int_Ref类型是access all Integer;
My_Int:整数;
我的配对:配对类型;
默认对:对类型:=(0,0);
包Int_Obj是新的Foo(Item=>Integer,
Item_Ref=>Int_Ref,
地址=>我的国际地址,
默认值=>0,
Is_Valid=>Int_Is_Valid);
包对对象是新的Foo(Item=>Pair\u类型,
项目参考=>对参考,
地址=>我的配对地址,
Default=>Default\u对,
Is_Valid=>Pair_Is_Valid,
验证=>Pair_Validate);
Tmp_Int:整数;
Tmps_对:对_型;
开始
Tmp_Int:=Int_Obj.Read_Eeprom;
Tmp_对:=对对象读取Eeprom;
端干管;
Im获取的错误是“需要文件结尾,文件只能有一个编译单元” 如何将通用子程序默认为作为包成员的函数?

不幸的是,您不能——这是一个鸡和蛋的问题。编译器需要弄清楚所有泛型参数是什么,然后才能实例化泛型参数;但是在实例化泛型之前,
Default\u Validate
方法将不可用。我认为最接近的方法是声明两个泛型:

generic
    type Item is private;
    type Item_Ref is access all Item;
    with function Validate (Data_Ptr : Item_Ref) return Boolean;   
package Foo is

    function Default_Validate (Data_Ptr : Item_Ref) return Boolean;
    -- etc.

end Foo;

generic
    type Item is private;
    type Item_Ref is access all Item;
package Foo_With_Default_Validator is
    -- important procedure/function declarations from Foo
end Foo_With_Default_Validator;

package body Foo_With_Default_Validator is
    function Default_Validate (Data_Ptr : Item_Ref) return boolean;
    package My_Foo is new Foo(Item, Item_Ref, Default_Validate);  
    function Default_Validate (Data_Ptr : Item_Ref) return boolean
        renames My_Foo.Default_Validate;
    -- and other procedures/functions will be renames of things from My_Foo
end Foo_With_Default_Validator;
(我还没有测试过这个。编辑:测试过,编译没问题。)我在这里假设Foo中唯一公开可见的东西是过程和函数。如果还有其他重要的特性(例如类型),它会变得更复杂,然后您可能必须使用嵌套泛型,其中
with function Validate
从外部泛型移到内部泛型,或者您可以使用泛型形式包将泛型分为两部分。在这两种情况中,泛型的用户可能必须执行两个实例化。如果上述解决方案有效,那么用户将使用默认验证程序对
Foo
Foo\u进行实例化,但可能是其中一个,也可能是另一个,不需要两个实例化。如果您需要更多帮助,我想我们需要查看
Foo
的可见部分

编辑2:如果您希望在实例化时需要一个
'Access
属性,这里有一个解决方案:

generic
    type Item is private;
    type Item_Ref is access all Item;
    Validate : access function (Data_Ptr : Item_Ref) return Boolean := null;   
package Foo is

    function Default_Validate (Data_Ptr : Item_Ref) return Boolean;
    -- etc.

end Foo;
然后在
Foo
的主体中,您将需要如下函数:

function Perform_Validate (Data_Ptr : Item_Ref) return Boolean is
begin
    if Validate = null
        then return Default_Validate (Data_Ptr);
        else return Validate (Data_Ptr);
    end if;
end Perform_Validate;
并在需要调用验证函数时,从身体的其余部分调用
Perform\u Validate
。(
Perform\u Validate
可以使用新的Ada 2012功能更简洁地编写,但你明白了。)

不幸的是,你不能——这是一个鸡和蛋的问题。编译器需要弄清楚所有泛型参数是什么,然后才能实例化泛型参数;但是在实例化泛型之前,
Default\u Validate
方法将不可用。我认为最接近的方法是声明两个泛型:

generic
    type Item is private;
    type Item_Ref is access all Item;
    with function Validate (Data_Ptr : Item_Ref) return Boolean;   
package Foo is

    function Default_Validate (Data_Ptr : Item_Ref) return Boolean;
    -- etc.

end Foo;

generic
    type Item is private;
    type Item_Ref is access all Item;
package Foo_With_Default_Validator is
    -- important procedure/function declarations from Foo
end Foo_With_Default_Validator;

package body Foo_With_Default_Validator is
    function Default_Validate (Data_Ptr : Item_Ref) return boolean;
    package My_Foo is new Foo(Item, Item_Ref, Default_Validate);  
    function Default_Validate (Data_Ptr : Item_Ref) return boolean
        renames My_Foo.Default_Validate;
    -- and other procedures/functions will be renames of things from My_Foo
end Foo_With_Default_Validator;
(我还没有测试过这个。编辑:测试过,编译没问题。)我在这里假设Foo中唯一公开可见的东西是过程和函数。如果还有其他重要的特性(例如类型),它会变得更复杂,然后您可能必须使用嵌套泛型,其中
with function Validate
从外部泛型移到内部泛型,或者您可以使用泛型形式包将泛型分为两部分。在这两种情况中,泛型的用户可能必须执行两个实例化。如果上述解决方案有效,那么用户将使用默认验证程序对
Foo
Foo\u进行实例化,但可能是其中一个,也可能是另一个,不需要两个实例化。如果您需要更多帮助,我想我们需要查看
Foo
的可见部分

编辑2:如果您希望在实例化时需要一个
'Access
属性,这里有一个解决方案:

generic
    type Item is private;
    type Item_Ref is access all Item;
    Validate : access function (Data_Ptr : Item_Ref) return Boolean := null;   
package Foo is

    function Default_Validate (Data_Ptr : Item_Ref) return Boolean;
    -- etc.

end Foo;
然后在
Foo
的主体中,您将需要如下函数:

function Perform_Validate (Data_Ptr : Item_Ref) return Boolean is
begin
    if Validate = null
        then return Default_Validate (Data_Ptr);
        else return Validate (Data_Ptr);
    end if;
end Perform_Validate;

并在需要调用验证函数时,从身体的其余部分调用
Perform\u Validate
。(
Perform\u Validate
可以使用新的Ada 2012功能更简洁地编写,但您已经明白了这一点。)

正如您所知道的,泛型定义了一个函数,
Default\u Validate
,因为关键字
函数
前面没有
with
。您应该拥有的是:

通用
类型项目是私有的;
类型
with
System,
SIGNATURE;

generic
    with package Item_Pkg is new SIGNATURE(<>);

    Addr     : System.Address;

    with function Is_Valid(X : Item_Pkg.Item) return Boolean is <>;
package Foo is
    use Item_Pkg;

    function Read_Eeprom return Item;
    function Is_Valid (Data_Ptr : access Item) return Boolean;

private
    Port : Item;    
    pragma Volatile( Port );
    Pragma Import( Convention => Ada, Entity => Port );

    For Port'Address Use Addr;
end Foo;
package body Foo is

    function Read_Eeprom return Item is
        Result : constant Item:= Port;
    begin
        if Is_Valid(Result) then
            return Result;
        else
            return Default;
        end if;
    end Read_Eeprom;

    function Is_Valid (Data_Ptr : access Item) return Boolean is
    begin
        return Is_Valid(Data_Ptr.all);
    end Is_Valid;

end Foo;
package Driver is
    MAX_INT                : constant Integer := 100;
    MIN_INT                : constant Integer := 0;

    -- Special / Non-Scaler Type
    type Pair_Type is 
    record
        X                  : Integer;
        Y                  : Integer;
    end record;

    -- Is Valid **USING OVERLOADS**
    function Is_Valid(Int  : Integer  ) return Boolean;
    function Is_Valid(Pair : Pair_Type) return Boolean;

    My_Int                 : Integer;
    My_Pair                : Pair_Type;

private
    Default_Pair           : constant Pair_Type := (0,0);
    Default_Integer        : constant Integer   := 0;
end Driver;
with
Foo,
SIGNATURE;

package body Driver is

    -- Is Valid
    function Is_Valid(Int  : Integer)   return Boolean is
        (Int <= MAX_INT and Int >= MIN_INT);

    function Is_Valid(Pair : Pair_Type) return Boolean is
        (Pair.X'Valid and Pair.Y'Valid);


    package Int_pkg  is new SIGNATURE(Integer,   0);
    package Pair_Pkg is new SIGNATURE(Pair_Type, Default_Pair);

    -- Using defaults for Is_Valid.
    package Int_Obj is new Foo (Item_Pkg  => Int_Pkg,
                                Addr      => My_Int'Address
                               );
    package Pair_Obj is new Foo(Item_Pkg => Pair_Pkg,
                                Addr     => My_Pair'Address
                               );

end Driver;