フォーラム


ゲスト  

ようこそ ゲスト さん。このフォーラムに投稿するには 登録が必要です。

ページ: [1]
トピック: 突然ですがクイズです
DEKO
管理者
投稿数: 2690
突然ですがクイズです
on: 2015/07/16 00:27 Thu

Q: 以下のようなソースコードがあります。

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i:=1 to 2 do
begin
// First time
{$I 'PrivateVar.inc'}
var
s: string;
begin
s := 'ABC' + IntToStr(i);
ShowMessage(s);
end
{$I 'PrivateVar.inc'}
// Second time
{$I 'PrivateVar.inc'}
var
s: string;
begin
s := 'DEF' + IntToStr(i);
ShowMessage(s);
end
{$I 'PrivateVar.inc'}
end;
end;

 
むむ!途中で変数が定義されていますね…こんなのはコンパイルが通りません。
ですが、PrivateVar.inc をうまく記述する事でコンパイルを通すことができます。さて PrivateVar.inc はどのように記述すればいいのでしょうか?

なお、実行結果は、

'ABC1'
'DEF1'
'ABC2'
'DEF2'

 
となります。また、コードの方は一切変更してはいけません。

# 対象となる Delphi は 2009 以降の Unicode 版を想定しています。
# 想定していた答えを検証してみたら XE4 以降でないと実行時にエラーになる
# ようなので (コンパイルエラーにはならない)、XE4 以降を対象とさせて頂きます m(_ _)m

DEKO
管理者
投稿数: 2690
突然ですがクイズです (解答編)
on: 2015/07/18 00:01 Sat

A: Delphi は 2009 以降で無名メソッド (匿名メソッド / Anonymous Method) が実装されています。
概要は DocWiki (http://docwiki.embarcadero.com/RADStudio/ja/%E7%84%A1%E5%90%8D%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89) を参照してもらうとして、無名メソッドは以下のような記述をする事もできます。

戻り値 := (関数)(引数, 引数…)
(手続き)(引数, 引数…);

 

関数の例:
var
ret: Integer;
begin
ret := (function (a: Integer): Integer
begin
result := a + 1;
end
)(2);
ShowMessage(IntToStr(ret));
end;

 

手続きの例:
begin
(procedure (a: Integer)
begin
ShowMessage(IntToStr(a + 1));
end
)(2);
end;

 
これが理解できれば、"展開後のコードをどう書けばいいのか?" は解ると思います。コードは以下のようになるはずです。

procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i:=1 to 2 do
begin
// First time
(procedure
var
s: string;
begin
s := 'ABC' + IntToStr(i);
ShowMessage(s);
end
)();
// Second time
(procedure
var
s: string;
begin
s := 'DEF' + IntToStr(i);
ShowMessage(s);
end
)();
end;
end;

 
こうですね。「これを *.inc で置き換えろ」という事ですから、最初のブロックは

(procedure

 
次のブロックは

)();

 
となります。*.inc を二つ使わずに単一の PrivateVar.inc でこれを展開させるには、{$I 'PrivateVar.inc'} が呼ばれる (という言い方も変ですが) たびにトグル動作させればいいわけです。そして答えはこうなります。

{$IFNDEF PASS_FLG}
(procedure
{$DEFINE PASS_FLG}
{$ELSE}
)();
{$UNDEF PASS_FLG}
{$ENDIF}

 
7行で過不足なく書けました。答えは合っていましたか?

See Also:
[Delphi(Object Pascal)でcaseを式にする (山本隆の開発日誌)]
http://www.gesource.jp/weblog/?p=6691
[[Delphi][TIPS]無名メソッドをその場で呼び出す。(全力わはー)]
http://d.hatena.ne.jp/tales/20091026/1256570237
[無名メソッドを使った局所関数 (Delphi Programming) (DEKO の雑談)]
http://ht-deko.com/ft1408.html#140812_04
[Delphi Include File (*.inc) (DEKO の雑談)]
http://ht-deko.com/ft1301.html#130125

DEKO
管理者
投稿数: 2690
解答: 細川さん
on: 2015/07/18 00:12 Sat
{$IFDEF installed} 
)();
{$UNDEF installed}
{$ELSE}
(procedure
{$DEFINE installed}
{$ENDIF}
DEKO
管理者
投稿数: 2690
解答: らいなタンさん
on: 2015/07/18 00:14 Sat
{$IFDEF _}
{$UNDEF _}
)();
{$ELSE}
{$DEFINE _}
TProc(procedure
{$ENDIF}

 
「Delphi 2010 ならこれで動くヨ!」とのコメントも頂いています。

DEKO
管理者
投稿数: 2690
Re: 突然ですがクイズです
on: 2015/07/18 00:29 Sat

引用 DEKO on 2015/07/18 00:14 Sat
「Delphi 2010 ならこれで動くヨ!」とのコメントも頂いています。

 
TProc でキャストした場合には Delphi 2009 でも動作するようです (検証済)。

{$IFNDEF PASS_FLG}
TProc(procedure
{$DEFINE PASS_FLG}
{$ELSE}
)();
{$UNDEF PASS_FLG}
{$ENDIF}

 
これなら当初の "Delphi 2009 以降で" という条件が満たせます。

ページ: [1]
WP Forum Server by ForumPress | LucidCrew
バージョン: 1.7.5 ; ページロード: 0.039 sec.