【问题标题】:How can I overload the '=' operator in Ada without creating a recursive function?如何在不创建递归函数的情况下重载 Ada 中的“=”运算符?
【发布时间】:2011-08-30 11:47:14
【问题描述】:
FUNCTION "=" (lString1, lString2 : IN lString) RETURN boolean IS


     IF lString1 = NULL AND lString2 = NULL THEN 
        RETURN true;
      ELSIF lString1 = NULL OR lString2 = NULL THEN
        RETURN false;
      END IF;

我正在尝试重载 Ada 中的相等运算符。每次我在函数中使用运算符“=”时,它都会导致递归,从而导致堆栈溢出,而不是使用我需要的 ada 定义的运算符。有没有办法将它与我的重载运算符区分开来?

【问题讨论】:

  • 这个问题有帮助吗? stackoverflow.com/questions/443009/…
  • 嗯,我以为你可以使用 Standard。"="(lString1, NULL),但 GNAT 对此犹豫不决,告诉我我有“不兼容的参数”。即使我将 null 替换为 lString 类型的常量(设置为 Null),我仍然遇到相同的错误。好奇...
  • @Will:不幸的是,我没有很好地阅读那段代码,因为 Ada 是我的第一门编程语言。
  • @Marc:我想有一种方法可以通过指定包来调用标准运算符,但我还没有想通。
  • 您不应为访问类型重载“=”。

标签: overloading ada


【解决方案1】:

通过引入非重载实用程序函数来进行访问类型比较,OP 的函数定义,以及所需的语法修复和修改以使用实用程序函数,可以工作。

不过,我仍然感到困惑,为什么将“=”作为标准调用。”= 会被编译器 (GNAT) 拒绝以指定“不兼容的参数”。

with Text_IO; use Text_IO;

procedure non_recursive_equals is

   type Lstring is access String;

   -- Be aware, the ordering of the functions here is important!
   function Is_Equal(Lstring1, Lstring2 : in Lstring) return Boolean is
   begin
      return Lstring1 = Lstring2;
   end Is_Equal;

   function "=" (lString1, lString2 : in Lstring) return Boolean is
   begin
      if Is_Equal(LString1, null) and Is_Equal(LString2, null) then
         return True;
      elsif Is_Equal(LString1, null) or Is_Equal(LString2, null) then
         return False;
      end if;
      return False;
   end "=";

   L1, L2 : Lstring := null;

begin
   Put_Line("L1 and L2 null: " & Boolean'Image(L1 = L2));
   L2 := new String(1..10);
   Put_Line("L2 not null   : " & Boolean'Image(L1 = L2));
end non_recursive_equals;

编辑:

这是另一种方式,使用重命名子句:

with Text_IO; use Text_IO;

procedure non_recursive_equals is

   type Lstring is access String;

   function Is_Equal (lString1, lString2 : in Lstring) return Boolean is
   begin
      if lString1 = null and lString2 = null then
         return True;
      elsif lString1 = null or lString2 = null then
         return False;
      end if;
      return False;
   end Is_Equal;

   function "=" (Lstring1, Lstring2 : in Lstring) return Boolean renames
     Is_Equal;

   L1, L2 : Lstring := null;

begin
   Put_Line ("L1 and L2 null: " & Boolean'Image (L1 = L2));
   L2 := new String (1 .. 10);
   Put_Line ("L2 not null   : " & Boolean'Image (L1 = L2));
end non_recursive_equals;

【讨论】:

  • 很好地解决了这个问题,如果你可以限制你使用 new = 函数的范围,这很有用。我认为尝试使其在更广泛的包体中或通过包规范可见会给我们同样的问题。
  • @Greg:很有可能。有人应该用这个问题来打 comp.lang.ada,因为那里有一些真正的语言律师(我现在无法从我所在的地方得到它)。我对尝试使用 Standard."=" 在函数内部进行比较时遇到的“不适当的参数”错误的原因特别好奇。 (为了自己看,在函数“=”中将每个对 Is_Equal 的引用替换为 Standard。“=”)
  • Marc C: 使用 gcc 4.3.4,Standard."="(Lstring1.all, "") 编译,但在运行时使用 access check failed 失败。 +1 示例,顺便说一句。
  • @MarcC:以类似的方式重载“+”将为codegolf.stackexchange.com/questions/28786/…提供一个很好的答案
【解决方案2】:

这是另一种方式,仅使用 Ada83... 和一个可怕的例子/滥用异常:

  Type LString is Access String;

  Function "=" (Left, Right: IN LString) Return Boolean is
     Subtype Constrained_LString is Not Null LString;

     Function Is_Equal( Left : LString; Right : String ) Return Boolean is
     begin
        Return Right = Left.All;
     exception
        When CONSTRAINT_ERROR => Return False;
     end Is_Equal;

  Begin
     Return Is_Equal(Left, Right.All);
  Exception
     When CONSTRAINT_ERROR =>
        begin
           Return Is_Equal(Right,Left.All);
        Exception
           When CONSTRAINT_ERROR => Return True;
        end;
  End "=";

如果调用它并且 Right = Null 尝试取消引用它会导致异常;在这种情况下,我们尝试取消引用 Left,如果这也失败了,那么两者都必须为 Null。 在只有一个失败的情况下,相等性必须为假,并且在两个参数都可以取消引用的情况下,结果是对这些字符串的相等性测试。

【讨论】:

    【解决方案3】:

    我能够使用类似的代码重现相同的行为。我冒昧地假设lString 是某种字符串access 类型

    我相信递归是由于您的新 = 函数掩盖了本机提供的函数这一事实引起的。由于它们共享相同的名称、参数和返回值,因此无法直接区分两者。

    解决这个问题的一种不优雅的方法是完全避免重载,并定义一个与重载函数具有相同行为的新函数,但名称不同,例如 Is_Equal

    【讨论】:

      【解决方案4】:

      我不确定为什么递归使用“=”;可能存在一个不幸的use 子句。下面的示例重载 "=" 并产生以下输出。重载函数隐式调用Standard."=" 进行比较。请注意,您可以指定 renames 来简化包名称,也可以指定 use type 来仅公开适用于某个类型的运算符。

      附录:我在下面的评论中添加了另一种调用 Standard."=" 的方法。

      控制台:

      ******************** ******************** 真的 真的

      代码:

      with Ada.Strings.Bounded;
      with Ada.Strings.Unbounded;
      with Ada.Text_IO;
      
      procedure UseType is
         package String20 is new Ada.Strings.Bounded.Generic_Bounded_Length(20);
         use type String20.Bounded_String;
      
         package StringN renames Ada.Strings.Unbounded;
         use type StringN.Unbounded_String;
      
         function "=" (Left  : String20.Bounded_String;
                       Right : StringN.Unbounded_String) return Boolean is
         begin
            return String20.To_String(Left) = StringN.To_String(Right);
            -- return Standard."="(String20.To_String(Left), StringN.To_String(Right));
         end "=";
      
         SB : constant String20.Bounded_String := 20 * '*';
         SN : constant StringN.Unbounded_String := 20 * '*';
      
      begin
         Ada.Text_IO.Put_Line(String20.To_String(SB));
         Ada.Text_IO.Put_Line(StringN.To_String(SN));
         Ada.Text_IO.Put_Line(Boolean'Image(SB = SN)); -- infix operator
         Ada.Text_IO.Put_Line(Boolean'Image("="(SB, SN))); -- named operator
      end UseType;
      

      【讨论】:

        【解决方案5】:

        您可能想使用 NOT EQUAL 运算符取反,也许?如果您对该运算符没有用处,那就是。 这可能你并不真正需要,因为它相当于not( X = Y )

        处理布尔代数应该是这样的:

        FUNCTION "=" (lString1, lString2 : IN lString) RETURN boolean IS
        
        
             IF not (lString1 /= NULL OR lString2 /= NULL) THEN 
                RETURN true;
              ELSIF not(lString1 /= NULL AND lString2 /= NULL) THEN
                RETURN false;
              END IF;
        

        PS:测试一下,我没有

        【讨论】:

          猜你喜欢
          • 2022-01-16
          • 2010-09-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-01-12
          • 2012-03-31
          • 1970-01-01
          相关资源
          最近更新 更多