我正在研究巴恩斯的出色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节,但没有任何意义。
干杯。
答案 0 :(得分:4)
我将总结到目前为止的发现(在Simon Wright和G_Zeus的帮助下)。如果我错了,请纠正我:
根据标准L = null
,R = null
,L = R
以及L.Next = R.Next
应该明确地调用用户定义的操作符=。 universal_access
运算符=绝对不能加入。
原因:
操作数L
,R
,L.Next
和R.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。