雑な k|m の生態について

その 31 - ネタにマジレス,してませんか?

2003-05-01

WM_MOUSEWHEEL の行方

さてさて「ユニコード文字を羅列するフォームに単純にツールバーを貼る」というスタイルはダサイので,「フォーム上にツールバーとユニコード文字表示コントロールが兄弟関係として存在する」というスタイルをとることにしました。ツールバーの上にはコンボボックスがあります。

ツールバーとユニコード文字表示コントロールを兄弟関係に / PNG イメージ,291x196

作業はすんなりと進んだわけですが,アプリケーションを起動,マウスホイールでスクロールさせようとしてもスクロールしません。コードを見直しても,確かにスクロール処理は怠っていません。スクロールバーのノブを引っ張れば確かにスクロールが可能です。

どうやら WM_MOUSEWHEEL メッセージは,フォーカスを持つウィンドウに送られるのが原因な模様。アプリケーションの開始直後はフォーカスは親ウィンドウにあるようで,いくらホイールを回してもユニコード文字表示コントロールには WM_MOUSEWHEEL は届きません。

解決策はこんなの:

メッセージを横流しする

親フォームが WM_MOUSEWHEEL を受け取った時,::SendMessage() でユニコード文字表示コントロールにメッセージを横流しします。・・親が子にメッセージを送るんだから「横流し」じゃないじゃん。

ただし,今回はフォントを選択するためにコンボボックスを取り付けていますが,こいつはクリックするとフォーカスを積極的に奪って行きます。親フォームにフォーカスを戻すために面倒なコードを書かなければならなくなるので萎え。この案はダメかも。

フォーカスを割り当てる

ユニコード文字表示コントロールを生成した後で,::SetFocus() でコントロールにフォーカスを割り当てれば万事解決なのです。それからコンボボックスがフォーカスを積極的に得ようとするので,そうですね,コントロールが WM_LBUTTONUP を受け取った時にも再度自分に ::SetFocus() をしてはどうでしょ?

この問題はこれで解決。明日は,貼り付けたコンボボックスにフォントを列挙させてみます。

2003-04-30

ToolbarWindow32 を使ってみた

2003-04-17 を最後にすっかり忘れてましたが,Unicode Viewer を作ってたんですね。ツールバーの表示まではイケたんで,ここにフォントを選択できるコンボボックスを乗っけましょう,と。

ていうかその前に,これではダサいのですよ

ツールバーとスクロールバーのダサい関係 / PNG イメージ 231x255

ツールバーが右端に行き着く前に,スクロールバーでさえぎられています。対して,常識的なアプリケーションはこう。イメージは「サクラエディタ」のものです。

ツールバーとスクロールバーの適切な関係 / PNG イメージ 196x197

イメージの Unicode Viewer は「メインのフォームに直接ユニコードを描画し,そのフォームの上にツールバーが存在する」というカタチでしたが,それではダサいのです。「メインのフォームの上にツールバーコントロールと“ユニコード表示コントロール”がある」という感覚でなければなりません。

うし。これを踏まえてコードを構成しなおす事にします。

2003-04-29

[ 車輪の ] 怒涛の DOM インスペクタ [ 再発明 ]

->怒涛の DOM インスペクタ

※日付が変わってしまったというか,むしろ今は 30 日の昼に近いので多少反則気味ですが気にしないー。

また犯ってしまいましたよ車輪の再発明。しかも今回は XML という最新技術に踏み込みいかなり過激な方向に進んでいます。もう誰にも文句は言わせません。

今回作ってみたのは DOM インスペクタ。内部ではちゃんと DOM レベル 1 をそこそこ実装している本格的な DOM オブジェクトを保持しており,その構造をツリービューにコピーしています。

->スクリーンショット

これは indexj.htm を読み込んでみた図。ちゃんと木構造が反映されているのが分かります。#text ノード内の文字列が化けていますが,これは EUC-JP に対応していないからですね。文字列変換ルーチンはいくつか存在するので,あとで組み込んでみようっと。

この DOM インスペクタには意外な使い道が。私が作っているサイトはほぼ全部 xhtml なので,この DOM インスペクタに放り込む事が出来ます。うまく木構造が反映されていなければ,十中八九,その xhtml ファイルの方で問題が発見されます。実際に今まで書いてきた雑記ファイルを食わせてみると,かなーり大量に記述ミスを見つける事ができました。我ながらすげぇ。

2003-04-28

プログラマ・アニメとバグ

プログラマを題材にした子供向けマンガ・アニメを考える

深夜なのにゲラゲラわらた ( 困る

プログラマ界隈ではなんとなく「宇宙のステルビア」というアニメ番組が話題の模様。中でも作品中のちょっとした台詞「バグが無いんです」には全国 100 億人のデスマーチャーたちが大興奮。「あり得ない!」「スタッフが暴挙に出た!」「これは架空の話だ!」「しーぽん萌え!」「あれは伝説だ!」「おめーら甘ぇ! バグ 0 を目指せ!」などと各人が言いたい放題なので,私にはそっちの方が笑えました。

次のコードにはバグがあります ( "[EOF]" は無視してくらさい )。

#include <stdio.h>

int main( int argc, char *argv[] ) {
  printf("hello, world!");
  return 0;
}[EOF]

実行するとコンソール画面に "hello, world!" と表示され,プロセスは戻り値として 0 を返します。ここには次のバグが挙げられます。

無くて七バグ。バグじゃなさげな項目もありますが,mozilla なんかでは「これを実装すれば cool じゃないか?」てな要望さえも bugzilla に登録される ── ユーザの要望を満たしていないのは "バグ" だと考える ── らしいんスけど。だからバグが数十万もカウントされるんスよね?

[ argv ]
どの有名オープンソースアプリケーションでしたっけ? 堂々と argv を書き換えているという話を聞いたことがあります。
[ kitchen-sink ]
"everything but the kitchen-sink" ( 流し台以外は全て ) は「何でもかんでも」という慣用句。「( なんでもかんでも詰め込んでいる ) mozilla には kitchen-sink がない」というバグ報告を受けて mozilla 1.3 は "And the kitchen sink, too..." を準備してこのバグの fix を試みました。しかし 1.4 には搭載されていないのか,about:kitchensink が存在しません。。。

2003-04-27

外来語うぜぇ?

25 日付けだったのかー。カタカナ語の言い換え提案が発出されました。おつかれさんだす>国語研究所の人たち。とりあえずこの雑記では気にしませんが,大衆向けの文章を書く場合は少しは気を使った方がよさげ?

そもそも昨今の奇妙なカタカナ語の氾濫は ( /. でも何人かの匿名さんが近い事を指摘していますが ) "偉い人" に対してプレゼンテーションを行う際に,ヘンに難しい英単語を使って "なんか分からんけど凄そうだ" という雰囲気を出し,最終的に "よし ( よく分からんが ) 分かった。キミに任せる!" なんてな展開を狙ったものではと。

少なくとも学問の世界ではなるべく新しいモノを理解するのが重要であって,日本語に容易に置き換える事が可能ならば躊躇無く置き換えらます。

関数,手続き
[ function, procedure ] 「プロシージャ」と言う事もありますが,その日本語訳は「手続き」でオケー。そういえば「ルーチン」はなぜか日本語訳されてない気が。
あ,「メソッド」も日本語訳されてないですねー。「挙動」・・とも違うし。
構造体,共用体,列挙型,反復子
[ struct | structure, union, enumerator, iterator ] 意外にも「ストラクト」という言葉は耳にしません。「リストラ」なんて言葉はあんなに流行ったのに。
反復子は「イテレータ」とも言われますが,きちんと広く知られている日本語訳も存在。
オブジェクト指向
[ object oriented ] 「物指向」とまでは訳されませんでしたが「オリエンテッド」とも言いません。微妙。
事の始まりは「プログラムの構造化」から考え方が拡張され,データ構造とアルゴリズムをまとめて記述しちゃう事でプログラミングの効率や可読性が向上できるよ,って感じですか? string オブジェクトを定義するならば,そこには文字列を保持するバッファと割り当て,連結,抽出,検索,比較のアルゴリズムをまとめて記述しておいたり。
最近はただオブジェクトを定義するのではなく,一旦「抽象的なモノ」を定義しておいて,そこから各部分を実装していく方法が主流。「イデア指向」という言葉はいかが?
実装
[ implement ] 「インプリメントする」という文もまれに見掛けますが,多くの人は「実装する」と言ってます。ますよね? 「インプリメンテーション」などと言ってる人はもう目も当てられませんよ?
継承
[ inheritance, derive ] 今さら「ディライブする」とは言いたくありません。それにしても「継承」って,イイ言葉を選んだなー。「導出」は多少もっさりしている感じがするのは,ただの馴れの問題かなあ。( 導出された〜 てな言葉も使われるけど )
委譲
[ delegation ] 英語で「デリゲーション」らしいですが,C# などでイベントハンドラをアレする「デリゲート」とはちょっと違う感じがしますね。この「委譲」はクラス A にクラス B の機能を持たせたいが,しかし継承はさせたくない場合に用いる手段。「性質の委譲」という表現は適切? 対して「デリゲート」は「処理の委譲」ですか。
C++ の「テンプレート」は委譲を用いたクラスで "コンパイル時の多態" を実現する,とんでもなく便利な機能。そだ,C++ でも std::mem_func を使って C# のようなデリゲートが可能との事なんで,後で遊んでみようかなあ。。。
多態
[ polymorphism ] これぞ技術用語の日本語訳の極み。「多態」なんて言葉,そう簡単に思いつくものではありません。間違えて「モルヒネいっぱい」とか訳さなくてよかったよ,本当に。

・・・うーん,日本語に訳しても,理解できないモンは理解できんのです。偉い人にはそれが分か以下略。

無理な日本語訳には抵抗を感じますが,「無理して外来語を使う」てな姿勢にも疑問。まあ,使いたい言葉を使えばいいってのがファイナルアンサーですかね,ソシュール大先生。

[ プレゼンテーション ]
言い換え案によると「発表」と。
[ イデア ]
プラトンのお言葉。万物に潜在的に存在する「本質」を意味する・・んですよね? 正円でも楕円でもぐにゃぐにゃの丸でも,私たちはその本質を「まる」と認識するわけで。
[ ソシュール ]
近代言語学の祖 ( おや )。私が尊敬する人物の一人です。

2003-04-26

[C++] 名前空間の障害 4 [解決編]

昨日のコードを動かしてみました。

:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(
:-(

ファッキュ。

・・当たり前ですわな。いくら static_cast<A::F*> したとは言え,thisthis。メソッド func()B::F にオーバーライドされているため,あのコードではいつまでも B::F::func() を呼び続けます。

何を考えたか ( 自分でもなぜこんな発想が出てきたのか分からない ) こんなコードを書きました。

#include <iostream>

struct A {
  struct F {
    virtual void func(){ std::cout << ":)" << std::endl; }
  };
};

struct B {

  typedef A::F super;  // やはり super を定義してみる

  struct F: public A::F {
    void func(){
      std::cout << ":-(" << std::endl;
      A::F *a_f = static_cast<A::F*>(this);
      a_f->super::func();  // ここ! a_f->A::F::func() ではコンパイルできない
    }
  };
};

int main( int ac, const char *av[] ) {

  A::F *f = new B::F();
  f->func();
  delete f;

  return 0;
}

これで OK。お疲れ様でした自分。

ちなみに a_f->super::func()a_f->F::func() と書いてもなぜか期待通りの動作をします。が,これはさすがに VC++ のバグの範疇かなあ。。。

2003-04-25

[C++] 名前空間の障害 3

昨日のコードをデバッガ上で実行すると,こんなんなっちゃいます。

->VC++ の断末魔

B::F"super" と別名をつけられた A::F を認知せず,一生懸命に自分自身を呼び出しています。健気なんだけど一発かましてやりたく存じますよ?

ここでなんとなく神が光臨。こういうトリックを思いつきました。もう typedef には頼りません。

#include <iostream>

struct A {
  struct F {
    void func(){ std::cout << ":)" << std::endl; }
  };
};

struct B {

  struct F: public A::F {
    void func(){
      A::F *a_f = static_cast<A::F*>(this);
      a_f->func();
    }
  };
};

int main( int ac, const char *av[] ) {

  B::F f;
  f.func();

  return 0;
}

なんと,これできちんと A::F::func() を呼び出してくれました。OK,キミは最高だよ。

・・おっと,ここで大切な事を忘れてた:本来,func()virtual にしたかったんスよー。A::F *f と宣言された変数に new B::F() をかますと,きちんと B::F でオーバーライドされた関数が呼ばれるのです。多態ってやしです。

#include <iostream>

struct A {
  struct F {
    virtual void func(){ std::cout << ":)" << std::endl; }
  };
};

struct B {

  struct F: public A::F {
    void func(){
      std::cout << ":-(" << std::endl;
      A::F *a_f = static_cast<A::F*>(this);
      a_f->func();
    }
  };
};

int main( int ac, const char *av[] ) {

  A::F *f = new B::F();
  f->func();
  delete f;

  return 0;
}

まず B::F::func() が呼ばれて欲しいんだけど,その中から「デフォルトの実装」である A::F::func() も使いたいって事でこんなコードになりました。さて,実行。

どうなるのか,勘の鋭い人ならもう分かりましたよね? とりあえず続きます。

[ VC++ の断末魔 ]
赤い「PNGイメージ」文字をちりばめているのは,もしこのイメージと同じデスクトップ配色の人がこれを見た時に,自分のパソコンでエラーが出てしまったと勘違いしてしまうのを防ぐためです。自分もさっきちょっとビビりました。

2003-04-24

[C++] 名前空間の障害 2

昨日の続きなんだけど,一つトリックを思いつきました。これならどうだ。

struct B : public A::F {
  typedef A::F super;

  void func(){
    super::func();
  }
};

ん,これなら成功。コンパイルも通り,期待通りの動作をします。しかし実は私がやりたかったのは次のようなコード。B::F の中から A::F の関数を呼びたいのです。一度 B を脱出して,しかるのちに A の中に突入です。

#include <iostream>

struct A {
  struct F {
    void func(){ std::cout << ":)" << std::endl; }
  };
};

struct B {
  typedef A::F super;

  struct F: public super {
    void func(){
      super::func();
    }
  };
};

int main( int ac, const char *av[] ) {

  B::F f;
  f.func();

  return 0;
}

おしっ,コンパイルが通った! 迷わず実行するぜ気合じゃをりゃぁああ!!1

・・あ,続きます。

[ 続きます ]
今ちょっとコーディングの方にハマっているので,雑記に時間をかけたくないのです。

2003-04-23

[C++] 名前空間の障害 1

そもそも C++ の仕様が複雑さを極めているため,完全に把握してる“人”でさえあまりいないんじゃないかな。いわんや,コンパイラをや。例え仕様を把握できたとしても,それを実装するのは至難の業ってわけですね。

VC++6.0 でもこれには対応していませんでしたが,こんなコード:

#include <iostream>

struct A {
  struct F {
    void func(){ std::cout << ":)" << std::endl; }
  };
};

struct B : public A::F {
  void func(){
    A::F::func();  // error C2352: 制的でないメンバ関数の中で ...
  }
};

int main( int ac, const char *av[] ) {

  B::F f;
  f.func();

  return 0;
}

コンパイルできません。コンパイラの出力するエラーは「制的でないメンバ関数の中で呼び出しが正しくありません」と日本語がちょっとアレですが,MSDN によるとつまり,static なクラス関数の中で何かしらのインスタンスが必要であるはずのメンバ関数が呼ばれたよという意味。

class C {
  void method() {} // 非 static なメンバ関数

  static void staticMethod() {
    method();  // error C2352
  }
};

このコードでこのエラーなら当然なのですが,ではなぜ前述のコードでこのエラーが? ・・要するにクラス B が「クラス A の中のクラス F」という,名前空間を一つまたいだ継承をしたからの模様。VC++6.0 ではまだこのあたりが弱いようで,少し残念だけど,クラス FA から出してやる必要があります。VC++7.0 では大丈夫なのかなあ?

んで,実はこのネタは続きます。

2003-04-22

[ぐちってます] 選挙とかアレとか

選挙戦が始まりました。いたるところで街宣車が走り回り,大声でなんかわめいてます。これこそが激しい馬と鹿のぶつかり合い。イイ事でも言ってるんならその存在意義を認めなくもないですが,彼らが街中で叫んでいるのはこう。

「foo 山 bar 男でございます」

「みなさんに支えられてきました」

「一生懸命,闘ってまいります」

「今こそうんたら制度の見直しを」

・・ンな抽象的な。Abstract な要求をするのは市民であって,それを適切に Implement するのが政治家の仕事ではないのかと。

「ご声援ありがとうございます」

うるせえよ。

std::sort()

そういえば,今までの仕事でソートを用いる事はほどんとありませんでした ( 去年の今頃にちょこっとだけ・・去年の雑記を参照 )。大抵はデータベースを扱う仕事だったんだけど,そんな場合は SQL でソートをかけちゃいますもんね。

そんなんじゃプログラマとして恥ずかしいので,ちょっとつまんでみました。

#include <algorithm>

struct Comp {
  int operator () ( const int& a, const int& b ) const
    { return 0; } // ここが笑うところ
};

int main() {

  int arr[] = { 9,4,0,57,3,4,92,34,7,3,9,8,414,0,9,5,872,4,510,65 };
  int count = sizeof arr / sizeof arr[0];

  std::sort( arr, arr + count, Comp() );

  for (int i=0; i < count; ++i )
    printf("%d,", arr[i] );

  return 0;
}

出力:

65,510,4,872,5,9,0,414,8,9,3,7,34,92,4,3,57,0,4,9,

ん。

2003-04-21

[C++] g++ で "_N" という識別子を使うと

昨日の続きです。テンプレート引数の識別子に _N という文字列を使いましたが,g++ では大抵のヘッダファイルをインクルードするとコンパイルできなくなります。

原因は ctype.h ファイルで見つかりました。

#define	_U	01
#define	_L	02
#define	_N	04
#define	_S	010
#define _P	020
#define _C	040
#define _X	0100
#define	_B	0200

こんなモノを定義してくれちゃっています。邪魔なんでボク undef しちゃいますよ?

・・・はい残念でした。このマクロはこんな風に使用されていて

#define isdigit(c)  (_ctype_+1)[(unsigned)(c)]&_N)

私がもし isdigit() を使いたくなった場合に,どうしても識別子 _N が必要になってしまいます。undef する事はご法度。要するに先頭がアンダースコアであるような識別子は,私たちが定義,使用するのはナンセンスだという事でファイナルアンサーの模様です。K & R でも書いてましたっけ?

[ ご法度 ]
実際,コンパイルできません。ctype_base.h でもこれらの識別子が使われているからですね。

2003-04-20

[C++] 型の不定なテンプレート引数で配列の要素数を指定すると

C++ のテンプレートは C のマクロ機能をほぼ置き換えるほどの威力なので萌え要素。他の言語でも搭載しちゃえばいいのに ( 悪魔の囁き )。

template< int N >
struct Array{ char array_[ N ]; };

上のコードはテンプレート引数に指定された個数の要素の配列を宣言できます。Array<12> a; てな具合にね。この方法は 2002-07-02 で作ってみた "SolidSequence" クラスでも使っています。

では,こんなコードはいかが?

template< typename T, T N >
struct Array{ char array_[ N ]; };

N の型を int ではなく,その前のテンプレート引数で指定するようにしてみました。これでもコンパイラは文句も言わずに仕事を行います。

じゃあ,こんなのも。

template< typename T, T N >
struct Array{ char array_[ N + 1 ]; };

N + 1 個の要素の配列を保持してもらいましょうか。・・ g++ では難なくコンパイルが通りましたが,我が "愛コンパイラ" VC++5.0 では 「C1001 内部コンパイラ エラー」が出てしまいました

ここまでのコンテキストで「なぜ?」を考えるのはもはやナンセンス ── コンパイラでさえ,何が悪いのかを明示できていないのです。よって回避策のみを考えます。こんなのはどうでしょ?

// 注意;VC++5.0 ではコンパイル可能だけど,
// g++ 3.2 ではコンパイルできません

#include <iostream> // g++ でコンパイルできなくなる原因 ( 後述 )

template< typename T, T _N >
struct Array{
  enum { N = _N };
  char array_[ N + 1 ]; };

enum ハックの威力ですねー。なんとか VC++5.0 のご機嫌をとり,コンパイルに成功します。しかし今度は g++3.2 でコンパイルが通らなくなりました。実はエラーメッセージを見てもなかなかわかり難いのですが,原因はテンプレート引数の識別子に使った _N にありそうな気配。

ああ,丁度時間が良さげなので,今日はこのへんで。

Written by kuri|minima(tkuri {at} fat.coara.or.jp) - all rights reserved.(warai
このリソースの位置情報は http://www.coara.or.jp/%7etkuri/D/031.htm で安定しています。