有没有办法在 Ada(特别是 GNAT)中创建和重用方面集?

Is there a way to create and reuse aspect sets in Ada (specifically GNAT)?

在 C/C++ 中,我经常使用预处理器来定义基于通用基础过程(是的,我知道,C 中的函数)的过程。

例如(名称、类型和值是假设的):

// in some .h file
void some_base_procedure(int a, char c);

#define proc1(a) some_base_procedure(a, 'd')
#define proc2(a) some_base_procedure(a, 'e')
#define proc3(a) some_base_procedure(a, 'f')

我看过 Ada 中的泛型并将它们用于包,但对于子程序我不确定如何干净地做类似于上面 C 示例的事情。

不过我确实想到了这个:

-- in some .ads file
procedure some_base(a:integer; c: character);

procedure proc1(a:integer; b: character := 'd') with
  Import    => True,
  Address   => some_base'Address;
procedure proc2(a:integer; b: character := 'e') with
  Import    => True,
  Address   => some_base'Address;
procedure proc3(a:integer; b: character := 'f') with
  Import    => True,
  Address   => some_base'Address;

这实际上工作得很好,我只需要在相关的.adb文件中为some_base实现一个主体,而不必实现只调用[的proc1、proc2、proc3子程序主体=66=] 使用正确的参数值。在我的一些用例中,虽然我有更多的方面,但只有导入和地址,所以这可能无法很好地扩展。

由于缺少更好的术语,我将这些称为参数化子程序别名

上述方法的一些问题:

  1. 仍然可以在调用 proc1、proc2 或 proc3 时覆盖 b。这是次要的,因为必须有意这样做(为了什么目的?)
  2. 它可能被认为通常不是 Ada 做事的方式(可能被认为是 C'ism)并且可能使用泛型是一种更简洁的方法,但是如果它涉及每个子程序单独的 ads/adb,那么对于如上所述的这种简单用例来说就太冗长了。
  3. 如果每个 参数化子程序别名 的方面变成多行,现在在维护期间更需要更新,并且成为一个类似的维护问题,因为每个 [= =40=]参数化子程序别名.

所以我的问题是关于上面最后一点的。

有没有办法将 Import => True, Address => some_base'Address; 放入某种方面集,然后为每个 参数化子程序别名 重新使用它?

所以它会像这样 (aspect_set, using some_base_set, .. .弥补了这个例子):

-- in some .ads file
procedure some_base(a:integer; c: character);
aspect_set some_base_set is Import    => True, Address   => some_base'Address;

procedure proc1(a:integer; b: character := 'd') using some_base_set;
procedure proc2(a:integer; b: character := 'e') using some_base_set;
procedure proc3(a:integer; b: character := 'f') using some_base_set;

即使没有,我认为我的上述方法已经足够好了,除非有人令人信服地指出为什么这是一个非常糟糕的方法,并且有一个更具表现力的 Ada做这样的事情的方式

在深入研究之后,我找到了一个更通用的解决方案。

-- in some .ads file
procedure some_base(a:integer; c: character);
procedure proc1(a:integer; b: character := 'd') renames some_base;
procedure proc2(a:integer; b: character := 'e') renames some_base;
procedure proc3(a:integer; b: character := 'f') renames some_base;

这比我使用的更干净,即使仍然可以覆盖默认值,但那是次要的。它解决了维护问题,这首先是问题的重点。

您在使用泛型时遇到什么问题?

generic
   C : Character;
procedure Some_Base(A : Integer);

procedure Some_Base(A : Integer) is
begin
   -- do something with A and B;
end Some_Base;


procedure Proc_1 is new Some_Base('d');
procedure Proc_2 is new Some_Base('e');
procedure Proc_3 is new Some_Base('f');