是否为匿名访问类型重载运算符“ =”?

时间:2019-01-11 21:36:32

标签: ada

我正在研究巴恩斯的出色Ada书。这是一个代码示例,用于深入比较第11.7节中的链接列表:

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

function "=" (L, R: access Cell) return Boolean is
begin
  if L = null or R = null then    -- universal =
    return L = R;                 -- universal = (Line A)
  elsif L.Value = R.Value then
    return L.Next = R.Next;       -- recurses OK (Line B)
  else
    return False;
  end if;
end "=";

我似乎无法确定为什么在行B中在行A中调用通用访问类型的运算符“ =” (由于偏好规则),但是<调用了strong>用户定义的运算符“ =” (首先使递归成为可能),这次没有优先选择universal_access的运算符“ =”。

L和R以及L.Next和R.Next都具有相同的匿名类型“ access Cell”。为什么“派遣”有所不同?它与L和R是访问参数有关吗?如果是这样,那里的规则是什么?

我竭尽所能在AARM中找到任何内容,尤其是第4.5.2节,但没有任何意义。

干杯。

2 个答案:

答案 0 :(得分:4)

我将总结到目前为止的发现(在Simon Wright和G_Zeus的帮助下)。如果我错了,请纠正我:

根据标准L = nullR = nullL = R以及L.Next = R.Next应该明确地调用用户定义的操作符=。 universal_access运算符=绝对不能加入。

原因:

操作数LRL.NextR.Next违反了ARM 4.5.2(9.1-9.4)中在这些表达式中解释=的前提unviversal_access类型的运算符=:

所有这些操作数均为对象类型(access Cell check ),其指定类型为Cell check ),Cell具有用户定义的原始等式运算符( check ),使得

  • 其结果类型为Boolean check );
  • 在与Cell相同的声明列表中立即声明( check );和
  • 其操作数中的至少一个是具有指定类型Cell的访问参数(两个操作数均为 check )。

ARM 8.6(29.1)universal_access类型的运算符=的优先规则在这里不适用,因为它需要“两个可接受的解释”。但是由于4.5.2,universal_access类型的operator =不能被接受。

因此别无选择:在所有情况下(甚至是L = null)都必须是用户定义的运算符=。

@Simon Wright:因此,“无界递归”实际上是正确的编译器行为。

@G_Zeus:为l = r发出歧义错误是错误的编译器行为,编译器应该选择Access_Equal."="

该示例应正确读取:

...

  if Standard."="(L, null) or Standard."="(R, null) then    -- universal =
    return Standard."="(L, R);                              -- universal =
  elsif L.Value = R.Value then
    return L.Next = R.Next;                                 -- recurses OK

...

干杯。

答案 1 :(得分:1)

我没有足够的声誉来评论OP,所以我将写一个答案。

有趣的是,我无法在Gnat 6.1.1中编译这样的示例(我改用Integer访问,但我怀疑它是否有任何意义)。 Gnat不断告诉我,Standard中的重载“ =”和通用“ =”之间的内联“ =”用法含糊。所以我尝试了:

package body Access_Equal is
   function "=" (L,R : access Integer) return Boolean is
   begin
      return Standard."="(L, R) or L.all = R.all;
   end "=";
end Access_Equal;

这似乎可以解决问题。我不能在代码中使用内联“ =”,但是,我必须使用完全限定的名称:

with Ada.Text_IO; use Ada.Text_IO;
with Access_Equal; use Access_Equal;
procedure Access_Equal_Test is
   l : access Integer := new Integer'(1);
   r : access Integer := new Integer'(1);
begin
   Put_Line(Boolean'Image(Standard."="(l, r))); -- FALSE
   Put_Line(Boolean'Image(Access_Equal."="(l, r))); -- TRUE
   Put_Line(Boolean'Image(l = r)); -- does not work
end Access_Equal_Test;

注意:使用Standard可能会带来可移植性,因为似乎不需要定义通用的“ =”。更多信息here