Generics 带有默认子程序的Ada通用包
我正在尝试创建一个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;
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;