【问题标题】:Can the = operator be overloaded for a private record type with generic members?可以为具有通用成员的私有记录类型重载 = 运算符吗?
【发布时间】:2012-10-21 13:26:16
【问题描述】:

我正在尝试为通用链表类重载相等运算符。以下是相关代码:

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;

这是我在 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中无限制地访问所有List函数.

【问题讨论】:

    标签: generics operator-overloading ada


    【解决方案1】:

    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。这就是它的用途。

    【讨论】:

      【解决方案2】:

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

      另外,请注意,在比较 Element 时,您必须比较值,而不是整个记录。 (参见带有 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
      

      【讨论】:

      • 刚刚试了一下(第一个代码块在 .ads 文件中,第二个在 .adb 文件中),它仍然给我同样的错误。
      • 好的,让我启动编译器,看看我能做什么。
      • 注意Use J...你也可以Use type J.List_Type
      • 谢谢,但我试图避免使用use 语句,因为如果一个过程中存在多个Test_List 包的实例化,则“=”函数仍然必须被限定。不过,在深入研究之后,我想我可能要求编译器提供太多的魔力。
      • sigh 让我明确地问...你试过use type吗?因为在我使用 J 为 Image [在示例中] 的调用添加前缀之后,它可以完美运行。
      猜你喜欢
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 2012-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多