为什么 Ada 中不允许匿名访问对象之间的隐式转换?

Tam*_*inn 6 operator-overloading ada

我正在阅读 Barnes 的书“Programming in Ada 2012”。这是实现第 12.5 节中的堆栈的代码示例。

src/stacks.adb:(主要相关文件)


package body Stacks is

   procedure Push(S: in out Stack; X: in Integer) is
   begin
      S := new Cell'(S,X);
   end Push;

   procedure Pop(S: in out Stack; X: in out Integer) is
   begin
      X := S.Value;
      S := Stack(S.Next);
   end Pop;

   function "="(S, T: Stack) return Boolean is
      SS: access Cell := S;
      TT: access Cell := T;
   begin
      while SS /= null and TT /= null loop
         if SS.Value /= TT.Value then
            return false;
         end if;
         SS := SS.Next;
         TT := TT.Next;
      end loop;
      return SS = TT; -- error: implicit conversion of stand-alone anonymous access object not allowed
   end "=";

end Stacks;
Run Code Online (Sandbox Code Playgroud)

我添加了一条评论,其中包含 gnat 给我的错误。为什么我不允许从一个匿名转换access Cell为另一个匿名?

我可以通过反转条件来解决问题:

return not (SS /= TT);
Run Code Online (Sandbox Code Playgroud)

这让我很困惑,因为约翰·巴恩斯之前说过,如果你定义一个返回布尔值的“=”运算符,那么会自动为你生成相反的“/=”,意思相反。

同样,循环条件可以反转,在这种情况下,它无法使用相同的消息进行编译。

最后,旁注:程序的预期行为,在更改为之后给出的return not (SS /= TT)是无限递归并由于堆栈溢出而引发 storage_error 。其原因可以在另一个 SO 问题中更好地看出,并且不是这个问题的主题。

为什么我写“=”时编译器不允许转换?为什么当我写“/=”时会有所不同,我认为它总是相反的?

自己编译示例所需的其他文件:

src/stacks.ads:

package Stacks is

   type Stack is limited private;

   procedure Push(S: in out Stack; X: in Integer);
   procedure Pop(S: in out Stack; X: in out Integer);
   function "="(S, T: Stack) return Boolean;

private

   type Cell is
      record
         Next: access Cell;
         Value: Integer;
      end record;
   type Stack is access all Cell;

end;
Run Code Online (Sandbox Code Playgroud)

src/main.adb:

with Ada.Text_IO; use Ada.Text_IO;
with Stacks; use Stacks;

procedure Main is
   A : Stack;
   B : Stack;
begin
   Push(A, 1);
   Push(B, 1);
   Push(A, 2);
   Push(B, 2);
   Push(A, 1);
   Push(B, 1);
   Push(A, 8);
   Push(B, 8);

   declare
      Same : Boolean := A = B;
      Text : String := (if Same then "They are the same" else "They are not the same");
   begin
      Put_Line(Text);
   end;
end Main;
Run Code Online (Sandbox Code Playgroud)

堆栈.gpr:

project stacks is
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");
end stacks;
Run Code Online (Sandbox Code Playgroud)

生成文件:

all:
    gprbuild -d -p -g

clean:
    rm -rf obj *.o *.ali
Run Code Online (Sandbox Code Playgroud)

或者用 gcc 编译:

gcc -c src/*.adb
gnatbind main
gnatlink main
Run Code Online (Sandbox Code Playgroud)

它给出相同的结果。