*nix環境でC++コードを書き殴るのに最高に便利なツールを作った

ファイル中にコンパイルフラグを含められるのと、そのままファイルを実行する形式でガンガン書けるので我ながら非常に便利に今のところ使えている。

ちょっとコードをテストしたいとかだと http://melpon.org/wandbox/ 使えば良いんだけど、FreeBSDではどうなるんだーSolarisではどうなるんだーとかいうのは Wandbox で書けないので。

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を弄るか。

↓動作例

melpon.org

mod_rewrite を使ってブラウザのURL欄には http://hoge.com/fuga と表示しつつページの中身は http://hoge.com/index.cgi/fuga を表示させる方法

.htaccess ファイルに以下のように書く

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.* - [L]
RewriteBase /
RewriteRule ^(.*)$ index.cgi/$1 [L]

Mojolicious::Lite を使ってて cgi だろうと単体で動かしてる時だろうと同じアドレスに出来るようにしたかったのが動機。

突然ひらめいたので小説を書きました

「やれやれ、この程度だったか」

僕はそう呟いてコミットをした。 バグ修正なので、コミットメッセージに「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 は持ってないので確認できません.

実行結果

f:id:nyaocat:20141008231349p:plain

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_referenceT, T&&T&& で返し、 T&T& で返す。

では何故 add_rvalue_reference<T>::typeT&T& で返すかというと、 N3337 の 20.9.7.2 曰く

This rule reflects the semantics of reference collapsing (8.3.2).

とのことです(丸投げ)。