パラメータとして任意の序数型をとるメソッドを書くことは可能ですか?Inc()またはHigh()と同じ方法ですか?
Delphi2007を使用しています
パラメータとして任意の序数型をとるメソッドを書くことは可能ですか?Inc()またはHigh()と同じ方法ですか?
Delphi2007を使用しています
型指定されていないパラメータを使用する必要があります:
procedure Foo(const ordinal);
また
procedure Foo(var ordinal);
もちろん、型システムを放棄したため、このようなルーチン内で実行できることには多少の制限があります。
可能な方法を見つけました、あなたが期待するものではないかもしれません、しかしねえ、私は方法を見つけました!を使用しVariants
ます。タイプレスパラメータをプロシージャに渡す際の問題は、タイプ情報がなく、プレーンポインタを取得するため、それを使用して有用なことを何もできないことです。バイトは1バイト、最大256要素の列挙は1バイトバイト、最大2 ^ 16要素の列挙は2バイト、整数は4バイトです(8でない限り)。しかし、何でも渡すことができ、物事を機能させるのに十分なタイプ情報を気にするタイプが1つありますVariant
。Delphi2010またはDelphiXEの優れた機能を誤って使用しないように、意図的に次の例をDelphi7で作成しました。
編集:によって序数と見なされるすべてのタイプを処理するようにコードサンプルを更新しましたVariants.VarTypeIsOrdinal
。これには、すべての整数型+ブール値が含まれます。どうやら列挙型はバイトとして見られるので、それもそれを飲み込みます。
program Project1;
{$APPTYPE CONSOLE}
uses
ExceptionLog,
SysUtils, Variants;
type TSomeEnum = (e0, e1, e2, e3, e4);
procedure DoSomethingWithEnum(V: Variant);
var i: Integer;
b: Byte;
lw: LongWord; // Cardinal!
i64: Integer;
begin
case VarType(V) of
varInt64:
begin
i64 := V;
WriteLn(i64);
end;
varSmallint, varInteger, varShortInt:
begin
i := V;
WriteLn(i);
end;
varByte:
begin
b := V;
WriteLn(b);
end;
varWord, varLongWord:
begin
lw := V;
WriteLn(lw);
end;
varBoolean:
begin
if V then WriteLn('True') else WriteLn('False');
end;
else WriteLn('NOT a variant type (type = #' + IntToStr(Ord(VarType(V))));
end;
end;
var i: Integer;
b: Byte;
c: Cardinal;
enum: TSomeEnum;
w: Word;
si: Shortint;
begin
i := 1;
b := 2;
c := 3;
enum := e4;
w := 5;
si := -6;
DoSomethingWithEnum(i);
DoSomethingWithEnum(b);
DoSomethingWithEnum(c);
DoSomethingWithEnum(enum);
DoSomethingWithEnum(True);
DoSomethingWithEnum(w);
DoSomethingWithEnum(si);
Readln;
end.
これを行うのが難しい理由は、Inc(x)、Dec(x)、およびPred(x)やSucc(x)のような他のものは、実際にはコンパイラーによって生成され、必要に応じて、単なる関数スタイルのシンタックスシュガーであるためです。固有のコンパイラ操作を介して。
一部の人々が示唆しているように、これの一部はオーバーロードを使用して、一部はジェネリックを巧妙に使用して、一部はバリアントを使用して実行できます。しかし、これらの機能をエミュレートするのに便利なものはなく、機能的にもまったく同じです。
コンパイラは、たとえば、Enum、Integer、およびそれらの型のサブ範囲を含むすべての順序付けされた型に対してInc()を実装します(従来の「Wirth」Pascalの今ではかなりあいまいな機能は、すべての型がそれらの型にサブ範囲を定義できることです)。
あなたが実際にあなたがしていることについてもっと私たちに話したなら、もっと近づくことができるかもしれません。しかし、一般的な答えは、いいえ、IncとDecのソースコードすらありません。これらはコンパイラプリミティブだからです。関数IncにRTLソースコードがあった場合は、それを調べて適応させることができます。
inc(x)はx:= Succ(x)として定義できますが、それでは、Succ(x)をどのように定義しますか?As x:= Inc(x)?分かりますか。ある時点で、コンパイラの「魔法」が引き継ぎます。