Swanman's Horizon

性欲をもてあましつつなんらかの話をするよ。

Use operator overloading for classes with non-ARC compiler

はじめに

演算子オーバーロードDelphi 2006で導入された機能で、自分が定義したレコードに+や-といった演算子の動作を実装できます。この機能はARC対応コンパイラであればレコードだけでなくクラスでも使えるんですが、非ARCコンパイラ、つまりx86向けのようなコンパイラでは使うことができませんでした。
ところが何気なくコードを書いていたところ、ちょっと違う書き方をするだけで演算子オーバーロードがクラスでも使えることを発見しました。また、同じ記述方法でクラスヘルパーやレコードヘルパーで演算子オーバーロードを後付けするという従来では完全に不可能だったことまでできるようになり、コーディングの幅が広がる可能性があります。

使い方

https://gist.github.com/lynatan/886ed984d230ac1b42dd89ed42ab2214

type
  TStringListEx = class(TStringList)
  public
    // class operator In(const A: string; B: TStringListEx): Boolean;
    class function &&op_In(const A: string; B: TStringListEx): Boolean; static;
  end;

  TPointHelper = record helper for TPoint // Possible in class helper!
  public
    // class operator Equal(const A: TPoint; const B: string) : Boolean;
    class function &&op_Equality(const A: TPoint; const B: string): Boolean; static;
  end;

class function TStringListEx.&&op_In(const A: string; B: TStringListEx): Boolean;
begin
  Result := B.IndexOf(A) >= 0;
end;

class function TPointHelper.&&op_Equality(const A: TPoint; const B: string): Boolean;
begin
  Result := Format('%d,%d', [A.X, A.Y]) = B;
end;

var
  sl: TStringListEx;
  pt: TPoint;
  ret: Boolean;
begin
  sl := TStringListEx.Create;
  sl.Add('AAA');
  sl.Add('BBB');
  ret := 'AAA' in sl;
  Writeln(BoolToStr(ret, True)); // -> 'True'

  pt := Point(123, 456);
  ret := pt = '123,456';
  Writeln(BoolToStr(ret, True)); // -> 'True'
  ...
end;

対応表

class operator class function
Implicit &&op_Implicit
Explicit &&op_Explicit
Negative &&op_UnaryNegation
Positive &&op_UnaryPlus
Inc &&op_Increment
Dec &&op_Decrement
LogicalNot &&op_LogicalNot
Trunc &&op_Trunc
Round &&op_Round
In &&op_In
Equal &&op_Equality
NotEqual &&op_Inequality
GreaterThan &&op_GreaterThan
GreaterThanOrEqual &&op_GreaterThanOrEqual
LessThan &&op_LessThan
LessThanOrEqual &&op_LessThanOrEqual
Add &&op_Addition
Subtract &&op_Subtraction
Multiply &&op_Multiply
Divide &&op_Division
IntDivide &&op_IntDivide
Modulus &&op_Modulus
LeftShift &&op_LeftShift
RightShift &&op_RightShift
LogicalAnd &&op_LogicalAnd
LogicalOr &&op_LogicalOr
LogicalXor &&op_ExclusiveOr
BitwiseAnd &&op_BitwiseAnd
BitwiseOr &&op_BitwiseOr
BitwiseXor &&op_BitwiseXOR
Include &&op_Include
Exclude &&op_Exclude

ところで

今ドキュメントを見ると最初から演算子オーバーロードはレコード向けに導入されたような記述がほとんどなんですが、Delphi 2006では普通にクラス向けに演算子オーバーロードが使えませんでしたっけ?次に買った2010ではしれっと無かったことになってて不思議だったんですが、結構大きな機能を削除されたわりにネット上で反応が全くと言っていいほど見られないので、僕の記憶がおかしいのかな…と思ってました。どっちなんだろう。記憶違いでした/(^o^)\