はじめに
数値計算でパラメータを読み込む必要がある時、毎回似たようなの書いている気がするので、C++のシングルヘッダファイルライブラリにまとめました1。
使い方
こんなパラメタファイルを考えます。
# Comment
bool=yes
int=12345
double=12.345
フォーマットは「key=value」で、#
から始まる行はコメントです。
こんな感じに読みこめます。
param::parameter param("input.cfg");
bool b = param.get<bool>("bool");
int i = param.get<int>("int");
double d = param.get<double>("double");
キーがない場合はエラーになりますが、キーが無いときにはデフォルトの値を使いたい場合は第二引数にデフォルト値を指定します。
bool b = param.get<bool>("non-existing key", false);
int i = param.get<int>("non-existing key", 0);
double d = param.get<double>("non-existing key", 0.0);
読み込みがこけたかどうかはif
文で判断します。
if (!param) {
std::cerr << "Could not find file " << filename << std::endl;
std::abort();
}
まぁ、それだけの、100行ちょっとのライブラリなんですけど。
雑談
数値計算やってて、なんかプログラムにパラメータを渡したいことがあります。数値計算なので、渡すパラメータはせいぜい真偽値、整数、浮動小数点数だけです。
例えば、システムサイズL
と温度T
を指定したい場合を考えましょう。サイズは整数、温度は浮動小数点数です。この時、様々なプログラムの結合度をもった与え方がありえます。
実行時引数
一番簡単なのは、実行時引数として与えてしまうことでしょう。
$ ./a.out 32 1.5
プログラム側はargv
とstd::stoi
とかstd::stod
を使って受け取ります。
さすがにこれはちょっとアレ感があるので、もう少しなんとかしたいところです。
ファイル(順番に並べる)
やはりパラメータはファイルに残しておきたい気がします。というわけで順番に並べておきましょう。
32
1.5
プログラムにはリダイレクトで渡してstd::cin
とかで受け取るんでしょうね。ファイルに吐いている分だけ、プログラムとの結合度は下がりましたが、パラメタが増えてくると「何番目がなんだっけ?」ということになるので、やっぱりパラメタに名前をつけたい気がします。
INIファイル形式
パラメタに名前をつけたいのでkey=value
という形式にしましょう。古のWindows INIファイルのセクションとかが無いやつみたいなイメージです。
L=32
T=1.5
パラメタに名前がついたので、順番が意味をもたなくなります。また、ファイル中にコメントが書けるようになるのが地味に便利です。ただし、データに階層構造をもたせることはできません。
JSON/YAML/XML
もう少しちゃんとやるなら、JSON/YAML/XMLといったファイルを使うことになるでしょう。ただ、それぞれC++のパーサはあるものの、やりたいことに比してちょっと道具立てが大仰かな、という気がします。
まとめるとこんな感じでしょうか。
まとめ
数値計算のインプットパラメタを簡単に渡すためのライブラリを書きました。今回、そろそろJSONかYAMLで行こうかな、と思ったのですが、わりと「重い」ライブラリしかなかったのと、書いてもどうせ100行程度なので自前で用意しました。ものすごく昔、XMLでパラメタを渡すプログラムがあって、ちょっと特殊な環境のマシンでlibxmlのビルドに苦労してから、どうも「重い」ライブラリに苦手意識があります。最近はまた状況が変わったんでしょうか。
-
車輪の再開発感半端ないですが・・・ ↩