如何在不创建递归函数的情况下重载Ada中的'='运算符?

时间:2011-05-22 06:10:07

标签: overloading ada

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定义运算符。有没有办法将它与我重载的运算符区分开来?

5 个答案:

答案 0 :(得分:4)

通过引入一个非重载的实用程序函数来进行访问类型比较,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;

答案 1 :(得分:3)

这是另一种方式,仅使用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。 在只有一个失败的情况下,相等性必须为假,并且在可以取消引用两个参数的情况下,结果是对这些字符串的相等性的测试。

答案 2 :(得分:2)

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

我认为递归是由于您的新=函数屏蔽了本机提供的函数。由于它们共享相同的名称,参数和返回值,因此没有直接的方法来区分两者。

一种不妥协的方法是避免完全重载并定义一个与重载函数具有相同行为的新函数,使用不同的名称,例如Is_Equal

答案 3 :(得分:1)

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

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

控制台:

********************
********************
TRUE
TRUE

代码:

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;

答案 4 :(得分:-1)

您可能想使用被否定的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:测试一下,我没有