2011-11-08 15 views
11

Delphi XE2では、レコードで表される値がセットの一部であるかどうかを確認できるようにレコードにin演算子をオーバーロードしようとしています。私のコードは次のようになります:Delphi 'in'演算子オーバーロードセット

type 
    MyEnum = (value1, value2, value3); 
    MySet = set of MyEnum; 
    MyRecord = record 
    Value: MyEnum; 
    class operator In(const A: MyRecord; B: MySet): Boolean; 
    end; 

class operator MyRecord.In(const A: MyRecord; B: MySet): Boolean; 
begin 
    Result := A.Value in B; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MySet; 
begin 
    R.Value := value1; 
    S := [value1, value2]; 
    Button1.Caption := BoolToStr(R in S); 
end; 

コードがコンパイルに失敗します。ステートメントR in Sの場合、コンパイラーは、互換性のないタイプMyRecordMyEnumと言っています。 R in Sは、上記のコードでTrueに評価されるように

にはどうすればMyRecordIn演算子をオーバーロードすることができますか?

+1

私はあなたが達成しようとしていることは可能ではないと思っています...あなたは余分な文字 ".Value" => BoolToStr(R.Value in S)とそれで完了する – ComputerSaysNo

+0

私の質問のコードは、単純なサンプルです。実際のアプリケーションでは、レコードタイプはセットタイプと1対1で対応していません。私が使い終わった回避策は 'InSet(S:MySet):Boolean'関数をレコードに追加し、' in'演算子の代わりにそれを使うことでした。 –

+0

多分、メンバー関数を作るのに十分なのではないでしょうか? 'BoolToStr(R._in(S));' –

答えて

1

を、しかし、あなたはしたくないことがあります。

だから次のように動作します。 AFAIK、クラス演算子は、それらが定義されているクラス(またはレコード)でのみ動作するので、コード内のRとSの両方がTMyRecordでなければなりません。暗黙的キャストの一部injudicious使用すると、我々は次を得る:

unit Unit2; 
interface 
type 
    MyEnum = (value1, value2, value3); 
    MySet = set of MyEnum; 
    MyRecord = record 
    Value: MyEnum; 
    ValueSet: MySet; 
    class operator Implicit(A: MyEnum): MyRecord; 
    class operator Implicit(A: MySet): MyRecord; 
    class operator In (Left,Right:MyRecord): Boolean; 
    end; 

implementation 

class operator MyRecord.Implicit(A: MyEnum): MyRecord; 
begin 
    Result.Value := A; 
end; 

class operator MyRecord.Implicit(A: MySet): MyRecord; 
begin 
    Result.ValueSet := A; 
end; 

class operator MyRecord.In(Left, Right: MyRecord): Boolean; 
begin 
    Result:= left.Value in Right.ValueSet; 
end; 
end. 

以下は今complile、とでも動作します:

私たちはすべて、同意するくらいです確信している、
procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MyRecord; 
begin 
    R.Value := value1; 
    S := [value1,value2,value3]; 
    Button1.Caption := BoolToStr(R In S,true); 
end; 

'BoolToStr(R.Value in S)'よりもエレガントです。 ただし、次もコンパイルされますが、誤った結果を与える:ドリンはちょうど鈍い、着実古い「BoolToStr(SでR.Value)」を持っている方が良い、コメントとして、だから、

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    S: MyRecord; 
begin 
    R.Value := value1; 
    S := [value1,value2,value3]; 
    Button1.Caption := BoolToStr(S In R,true); 
end; 

を。もちろん、コード行ごとに支払われている場合を除きます。バグ修正のためのボーナス。

+0

この特定の質問は、これまで使用していなかったクラス演算子を考え出す練習に過ぎませんでした。私が取り組んでいた実際のコードのレコードタイプはずっと複雑です。それが定義する演算子は、そのレコードを使用するコードをはるかに簡単にすることを可能にします。数百行の単純な演算子関数により、複雑なコードの何千もの行がはるかに読みやすくなります。 –

+0

申し訳ありませんが、私のコメントは多少面白かったです。私は、レコードのための新しい演算子の読み込みと非常に取られて、それを広く使用していることを認めます。そして、多くの場合、コードをはるかに明確にすることに同意します。私は自分自身の解決策で楽しいものを掘り下げていました。この具体的なケースでは残念です;-) – HMcG

+0

"コード内のRとSの両方がTMyRecordでなければなりません"これは間違っています。 – Johan

5

in演算子が正しく動作するためには、演算子はバイナリ演算子ではなく、セット演算子であるため、レコード型でなければなりません。あなたのケースでは、それは左のオペランドです。あなたはほとんどはこれを行うことができ、まあ

type 
    MyRecord = record 
    Value: MyEnum; 
    class operator In(const A: MyRecord; const B: MySet): Boolean; 
    end; 

    MyRecord2 = record 
    Value: MySet; 
    class operator In(const A: MyRecord; const B: MyRecord2): Boolean; 
    class operator In(const A: MyEnum; const B: MyRecord2): Boolean; 
    end; 

class operator MyRecord.In(const A: MyRecord; const B: MySet): Boolean; 
begin 
    Result := A.Value in B; 
end; 

class operator MyRecord2.In(const A: MyRecord; const B: MyRecord2): Boolean; 
begin 
    Result := A.Value in B.Value; 
end; 

class operator MyRecord2.In(const A: MyEnum; const B: MyRecord2): Boolean; 
begin 
    Result := A in B.Value; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    R: MyRecord; 
    R2: MyRecord2; 
begin 
    R.Value := value1; 
    R2.Value := [value1, value2]; 

    if R in R2 then; 
    if value1 in R2 then; 
end;