Ada 访客设计模式和泛型

Ada visitor design pattern and generics

提问人:Albatros23 提问时间:3/16/2023 最后编辑:Albatros23 更新时间:3/16/2023 访问量:118

问:

我正在实现一个访问者模式,并且我有一些元素可以使用泛型实现,但 GNAT 编译器抱怨泛型类型。 我有一个使用通用混合的解决方案,但它不太直观。

我该如何解决?

我提供了以下最小的可重复示例:

  1. 访客.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;
  1. 元素.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;
  1. 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;
  1. 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;
  1. 实例化.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;

我可以正确实现第一个选项,还是应该使用混合来实现它?

提前感谢您,并对代码的大量使用表示歉意。

泛型 ADA 访客模式

评论


答:

2赞 Jere 3/16/2023 #1

我不认为你可以按照你最初想要的方式去做。Ada 中的泛型实例化都是单独的类型,即使它是泛型的相同输入(不像在 C++ 中,类型相同)。因此,Instantiation.GenericElement_t 类型的 Visitors 包中的参数在技术上与泛型中的版本不同,泛型内部的版本还没有特定类型(因为它位于泛型内部,没有实例化)。

我不知道混合是否是唯一的策略。可能还有其他方法可以重新组织它以更好地工作,但我不知道有什么现成的,所以如果没有其他人有更好的计划,你可能会被困在混合中。

评论

0赞 Albatros23 3/16/2023
感谢您@Jere的回答。对我来说,混入是可以的,但对于一些没有经验的审稿人来说,可能很奇怪,难以理解