可以将=运算符对具有通用成员的专用记录类型重载



我正在尝试将通用链接列表类的相等运算符超载。这是相关代码:

list.ads:

generic
    type Element_Value_Type is private;
package List is
    type List_Type   is private;
    type Element     is private;
    type Element_Ptr is private;
    function "=" (L, R : List_Type) return Boolean;
    --  Other linked list function declarations  --
private
    type Element is
        record
            Value : Element_Value_Type;
            Next  : Element_Ptr;
            Prev  : Element_Ptr;
        end record;
    type Element_Ptr is access Element;
    type List_Type is
        record
            Length : Integer     := 0;
            Head   : Element_Ptr := null;
            Tail   : Element_Ptr := null;
        end record;
end List;

list.adb:

package body List is
    function "=" (Left, Right : List_Type) return Boolean is
    begin
        --  Code for equality checking  --
    end "=";
    --  Other function implementations  --
end List;

main.Adb:

with Text_IO;
with List;
use Ada;
procedure Main is
    package Int_Lists is new List (Integer);
    procedure Print_List (List : Int_Lists.List_Type) is
    begin
        --  code to print the contents of a list  --
    end
    L1, L2 : Int_Lists.List_Type;
begin
    Int_Lists.Append (L1, 1);
    Int_Lists.Append (L2, 1);
    Int_Lists.Append (L1, 2);
    Int_Lists.Append (L2, 2);
    Text_IO.Put_Line (Item => Boolean'Image (L1 = L2));
end Main;

这是我在主体的最后一行中遇到的错误:

operator for private type "List_Type" defined at list.ads:X, instance at line X is not directly visible

有什么方法可以让它看到" ="函数?如果我执行Int_Lists."=" (L1, L2),或者如果我将use Int_Lists放在Main主体之前,则有效,但是第一个击败了操作员过载的目的,而第二种允许从MAIN内部进行所有列表功能的无限访问。

Main中,

之后
package Int_Lists is new List (Integer);

您可以写

use type Int_Lists.List_Type;

function "=" (L, R : Int_Lists.List_Type) return Boolean
  renames Int_Lists."=";

就个人而言,我要去use type。这就是它的目的。

是的,您可以使用私有类型的通用参数使用" =",但是我建议我与私有类型一起传递" ="函数,但默认为可见的函数,with function … is <>表示。

另外,,请注意,在比较Element时,您必须比较值,而不是整个记录。(请参阅具有元素参数的" ="的定义;它是ADA 2012表达式功能之一。)

Test_List.ads

generic
    type Element_Value_Type is private;
    with function "=" (Left, Right : Element_Value_Type) Return Boolean is <>;
    -- Image only for debugging.
    with function Image( Value : Element_Value_Type ) Return String;
package Test_List is
    type List_Type   is private;
    type Element     is private;
    type Element_Ptr is private;
    function "=" (L, R : List_Type) return Boolean;
    Procedure Append(List : in out List_Type; Item : Element_Value_Type);
    function Image( List : List_Type ) Return String;
private
    type Element is
        record
            Value : Element_Value_Type;
            Next  : Element_Ptr;
            Prev  : Element_Ptr;
        end record;
    function "=" (Left, Right : Element ) Return boolean is
    ( Left.Value = Right.Value );

    type Element_Ptr is access Element;
    type List_Type is
        record
            Length : Integer     := 0;
            Head   : Element_Ptr := null;
            Tail   : Element_Ptr := null;
        end record;
end Test_List;

Test_List.adb

Package Body Test_List is
    function "=" (L, R : List_Type) return Boolean is
    begin
    Return Result : Boolean:= L.Length = R.Length do
        -- We only need to check if lengths are equal.
        if not Result then Return; end if;
        declare
        SubType NN_Element_Ptr is Not Null Element_Ptr;
        L_Cursor : NN_Element_Ptr:= L.Head;
        R_Cursor : NN_Element_Ptr:= R.Head;
        begin
        loop
            if L_Cursor.Value /= R_Cursor.Value then
            Result:= False;
            Return;
            end if;
            Exit when L_Cursor = L.Tail;
            L_Cursor:= L_Cursor.Next;
            R_Cursor:= R_Cursor.Next;
        end loop;
        end;
    exception
        when Constraint_Error =>
        -- Handle empty lists.
        Result:= L.Tail = R.Tail;
    End return;
    end "=";
    Procedure Append(List : in out List_Type; Item : Element_Value_Type) is
    begin
    List.Tail:= new Element'(
            Value => Item,
            Next  => null,
            Prev  => List.Tail
             );
    -- If this is the inital element we link head to ie, if not we need
    -- to link the previous tail's next-pointer to the current tail.
    if List.Length = 0 then
        List.Head := List.Tail;
    else
        List.Tail.Prev.Next:= List.Tail;
    end if;
    List.Length:= List.Length + 1;
    end Append;
    Function Image( List : List_Type ) Return String is
    Separator : Constant String := ", ";
    Function Image( Item : Element_Ptr ) Return String is
    begin
        if Item = Null then
        Return "";
        else
        Return Image(Item.Value) & Separator & Image(Item.Next);
        end if;
    end Image;
    Temp : String:= Image( List.Head );
    begin
    Return '(' & Temp(temp'First..temp'Last-Separator'Length) & ')';
    end Image;
End Test_List;

test.adb

With
Test_List,
Ada.Text_IO;
Procedure Test is
    Package J is new Test_List( Integer, Image => Integer'Image );
    L1, L2 : J.List_Type;
    Use J;
Begin
    Ada.Text_IO.Put_Line( Image(L1) );
    J.Append (L1, 1);
    J.Append (L2, 1);
    J.Append (L1, 2);
    J.Append (L2, 2);
    J.Append (L1, 3);
    J.Append (L2, 3);
    Ada.Text_IO.Put_Line( Image(L1) );
    Ada.Text_IO.Put_Line( "List equality: " & Boolean'(L1 = L2)'Img );
    J.Append (L2, 1);
    J.Append (L1, 2);    
    Ada.Text_IO.Put_Line( "List equality: " & Boolean'(L1 = L2)'Img );
End Test;

输出是:

()
( 1,  2,  3)
List equality: TRUE
List equality: FALSE

最新更新