提问人:Albatros23 提问时间:3/16/2023 最后编辑:Albatros23 更新时间:3/16/2023 访问量:118
Ada 访客设计模式和泛型
Ada visitor design pattern and generics
问:
我正在实现一个访问者模式,并且我有一些元素可以使用泛型实现,但 GNAT 编译器抱怨泛型类型。 我有一个使用通用混合的解决方案,但它不太直观。
我该如何解决?
我提供了以下最小的可重复示例:
- 访客.ads
with ConcreteElements;
with Instantiation;
package Visitors is
type Visitor_t is interface;
procedure pVisit (this : in Visitor_t;
element : ConcreteElements.ConcreteElement_t) is abstract;
procedure pVisit (this : in Visitor_t;
element : Instantiation.GenericElement_t) is abstract;
end Visitors;
- 元素.ads
limited with Visitors;
package Elements is
type Element_t is abstract tagged null record;
procedure pAccept
(this : in Element_t;
visitor : in Visitors.Visitor_t'Class) is abstract;
end Elements;
- concreteelements.ads/adb
limited with Visitors;
with Elements;
package ConcreteElements is
type ConcreteElement_t is new Elements.Element_t with null record;
overriding
procedure pAccept
(this : in ConcreteElement_t;
visitor : in Visitors.Visitor_t'Class);
end ConcreteElements;
with Visitors;
package body ConcreteElements is
procedure pAccept
(this : in ConcreteElement_t;
visitor : in Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end ConcreteElements;
- genericelements.ads/adb
with Elements;
limited with Visitors;
generic
type Parent_t (<>) is abstract new Elements.Element_t with private;
package GenericElements is
type GenericElement_t is new Parent_t with null record;
overriding
procedure pAccept (this : in GenericElement_t;
visitor : in Visitors.Visitor_t'Class);
end GenericElements;
with Visitors;
package body GenericElements is
procedure pAccept (this : in GenericElement_t;
visitor : in Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end GenericElements;
- 实例化.ads
with GenericElements;
with Elements;
package instantiation is new GenericElements
(Parent_t => Elements.Element_t);
编译器在 4) 的正文中抱怨,在第 9 行:
预期类型“实例化。GenericELement_t“在 genericelements.ads:8 中定义
找到在 genericelements.ads:8 中定义的类型“GenericElements.GenericElement_t”
我的解决方案是执行混合,使GenericElement_t抽象,因此这将是 1)、4) 和 5):
1)
with ConcreteElements;
with Instantiation;
package Visitors is
type Visitor_t is interface;
procedure pVisit (this : in Visitor_t;
element : ConcreteElements.ConcreteElement_t) is abstract;
procedure pVisit (this : in Visitor_t;
element : Instantiation.Instantiation_t) is abstract;
end Visitors;
with Elements;
generic
type Parent_t (<>) is abstract new Elements.Element_t with private;
package GenericElements is
type GenericElement_t is abstract new Parent_t with null record;
end GenericElements;
private with GenericElements;
limited with Visitors;
with Elements;
package instantiation is
type Instantiation_t is new Elements.Element_t with private;
overriding
procedure pAccept (this : in Instantiation_t;
visitor : Visitors.Visitor_t'Class);
private
package instantiation_pck is new GenericElements
(Parent_t => Elements.Element_t);
type Instantiation_t is new instantiation_pck.GenericElement_t with null record;
end instantiation;
with Visitors;
package body instantiation is
procedure pAccept (this : in Instantiation_t;
visitor : Visitors.Visitor_t'Class) is
begin
visitor.pVisit(this);
end pAccept;
end instantiation;
我可以正确实现第一个选项,还是应该使用混合来实现它?
提前感谢您,并对代码的大量使用表示歉意。
答:
2赞
Jere
3/16/2023
#1
我不认为你可以按照你最初想要的方式去做。Ada 中的泛型实例化都是单独的类型,即使它是泛型的相同输入(不像在 C++ 中,类型相同)。因此,Instantiation.GenericElement_t 类型的 Visitors 包中的参数在技术上与泛型中的版本不同,泛型内部的版本还没有特定类型(因为它位于泛型内部,没有实例化)。
我不知道混合是否是唯一的策略。可能还有其他方法可以重新组织它以更好地工作,但我不知道有什么现成的,所以如果没有其他人有更好的计划,你可能会被困在混合中。
评论
0赞
Albatros23
3/16/2023
感谢您@Jere的回答。对我来说,混入是可以的,但对于一些没有经验的审稿人来说,可能很奇怪,难以理解
评论