首页 > 解决方案 > 为什么在 Ada 中不允许匿名访问对象之间的隐式转换?

问题描述

我正在阅读 Barnes 的《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;

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

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

return not (SS /= TT);

正如约翰·巴恩斯(John Barnes)早些时候所说,如果您定义一个返回布尔值的“=”运算符,这让我感到困惑,那么会自动为您生成反的“/=”,这意味着相反。

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

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

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

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

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;

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;

堆栈.gpr:

project stacks is
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("main.adb");
end stacks;

生成文件:

all:
    gprbuild -d -p -g

clean:
    rm -rf obj *.o *.ali

或者用 gcc 编译:

gcc -c src/*.adb
gnatbind main
gnatlink main

它给出了相同的结果。

标签: operator-overloadingada

解决方案


推荐阅读