bash の trap を複数指定する方法
bashスクリプトでシグナルハンドラを定義出来るtrap
は大変便利だが、trap
を複数回呼び出すと最後に書いたtrap
の内容で上書きされてしまう。
↓例 melpon.org
別段シグナルハンドラを複数定義したいことも普通は無いが、0 番(終了時に必ず呼ばれる)には結構指定したいものが増えがちではないだろうか。
そこで、自前で複数保持出来るtrap
を今即興で書きました
# zlib/libpng License TRAP_COMMAND_STR=() function trap() { TRAP_COMMAND_STR[$2]="${TRAP_COMMAND_STR[$2]} $1 ;" builtin trap "${TRAP_COMMAND_STR[$2]}" $2 }
どんどん;
で区切って追加することで実現している。
なお、これだとシグナルハンドラのリセットが出来ないのでまぁそういう時はbuildin trap
か自前のtrapを弄るか。
↓動作例
突然ひらめいたので小説を書きました
「やれやれ、この程度だったか」
僕はそう呟いてコミットをした。 バグ修正なので、コミットメッセージに「fix #615」とだけ記述。 そして僕の手は次のコマンドを git push origi…… と軽やかにタイプしていく。
僕は暇な大学生プログラマだ。時々そこら辺に公開されているソフトウェアのバグ修正をしたり機能追加を手伝ったりしている。 自慢じゃないが、プログラミングの講義を受けながらプログラミングが出来ない同じ大学の学生の中では僕はトップの技術力だろう。
タイプは1.3秒で終わった。これでまた僕の成果がひとつ増えるな、そう思いながら僕の手はEnterを押して……違和感。
push が失敗した。
まぁ、このバグ修正に取り掛かってから途中ゲームをしたりしていた。誰かが既に push していたのだろう。さして疑問を抱くこともなく僕は rebase をすることにした。git fetch origin。エンター。git rebase -i origin/master。エンター。違和感。
「なんだこれは?」
僕は最新のコミットの上に自分のコミットが連なるよう整理をしようとしたのだが、おかしい。僕が見ていない間に積み重ねられたコミットが多過ぎる。 僕が修正していた時間はそこまで長くないはずだが……?
コミットの詳細をよく見ることにしよう。gitk --all。エンター。……これは、全て一人によるコミットだと!?
……これが、後に僕の人生を揺るがす、激カワ猫耳ダウナー系フリルふりふりツインテールあざと美少女メイドプログラマーとの初遭遇だった……
gtkmm と SDL2 を組み合わせて使う
能書き
Gtk+ には特殊なウィジェットとして socket, plug ウィジェットがあり, 親プロセスの持つ socket ウィジェット内に 別プロセスから plug ウィジェットを用いて描画させることが出来る.
これだけでも充分面白いが,socket ウィジェットはウィジェットでありながら内部にウィンドウシステムのネイティブなウィンドウハンドルを持っているため,アンドキュメントだが plug ウィジェットに限らず他のGUIツールキットからでも描画させることが出来る.
SDL2には複数ウィンドウを作る機能があり,ウィンドウを作成する方法としてSDL_CreateWindowFrom
を用いると既存のウィンドウハンドル上にSDLのウィンドウを作成出来る.
今回はこの二つを組み合わせてみた.
プラットフォーム
この記事では(書くのがめんどくさいので) Linux 上での実行方法・コードだけ載せるが SDL2 も GTK もこれらの機能はクロスプラットフォームで提供しているので Windows でも Mac でもウィンドウハンドルの型を変えることによって同様の結果を得られる……はずである.多分.
Windows では HWND を使って動作することを確認したが,Mac は持ってないので確認できません.
実行結果
VM内の Ubuntu で実行.Gtk で作成されたウィンドウのいちウィジェット内に SDL2 で描画している.
コード,コンパイル,実行方法
続きを読むdeclval<T>() の返り値型が T&& である理由
メモ。
そもそも declval
とは?
型T1
, T2
があり、それらの値を乗算した結果の型を得たい場合、
素直に考えると
decltype( T1() * T2() )
で得られそうだが、これは T1, T2 共にデフォルトコンストラクタが無いと
T1()
,T2()
がコンパイルエラーになってしまう。
そこで std::declval
が使える。
decltype( std::declval<T1>() * std::declval<T2>() )
以下略
もし返り値型が T
だった場合
struct Widget;
template<class T>
T my_declval();
decltype( my_declval<Widget>() * my_declval<Widget>() ) val;
T
が不完全型の時にエラーになる。
もし返り値型が T&
だった場合
struct Widget {
Widget(Widget const&) = delete;
Widget(Widget&&);
};
template<class T>
T& my_declval();
int somefunc( Widget );
// エラー!
decltype( somefunc( my_declval<Widget>() ) ) val1;
// OK
decltype( somefunc( std::move(my_declval<Widget>()) ) ) val1;
ムーブ構築しか出来ない場合に面倒くさくなる。
補足
尚、 declval
は基本的に T&&
を返すので
int somefunc( int& );
decltype( somefunc( std::declval<int>() ) ) val;
このコードがエラーになる(msvcだと通っちゃうんだけど)。 こういう場合は、
int somefunc( int& );
decltype( somefunc( std::declval<int&>() ) ) val;
と、渡す型に & を付けてやれば良い。
これが何故通るかというと、実は declval
の返り値型は add_rvalue_reference<T>::type
だからである。
add_rvalue_reference
は T, T&&
を T&&
で返し、 T&
を T&
で返す。
では何故 add_rvalue_reference<T>::type
は T&
を T&
で返すかというと、
N3337 の 20.9.7.2 曰く
This rule reflects the semantics of reference collapsing (8.3.2).
とのことです(丸投げ)。
SDL2 の適当なサンプルコード
とりあえず動くコードをメモしとくと後で環境構築したときに本当に動くのかパパッと確認するときにたまに役に立つ
続きを読むRedmine Startpage plugin で任意のプロジェクトの「概要」ページを指定する方法
Controller: projects
Action : show
Id : プロジェクト名
特定の Wiki ページをトップに指定する方法しかWeb検索だと出てこない……