debug_num_put

昨日のパース関連の続きです。
C++で簡単なパースを行う場合、I/Oストリームの書式付き入出力が便利です。

void func1(std::istream& is)
{
    // 入力例: "123 456"
    int a, b;
    is >> a >> b;
}

しかし、この方法はストリームに吹き込まれているロケールによって結果が変わってしまいます。
また、

void func2(const char* filename)
{
    std::ifstream is(filename);

    int a, b;
    is >> a >> b;
}

のようなパターンでもグローバルロケールが吹き込まれるため、よくありません。
「普通」にパースするためには、

void func3(const char* filename)
{
    std::ifstream is(filename);
    is.imbue(std::locale::classic()); // これが必要

    int a, b;
    is >> a >> b;
}

のようにクラシックロケールを明示的に吹き込む必要があります。


こうした意図しないロケールの利用を見つけるために、デバッグ用のnum_get/num_putを作りました。
<hamigaki/debug_facets.hpp>
使い方はmain()関数の先頭などで、

std::locale loc0(std::locale(), new hamigaki::debug_num_get);
std::locale loc(loc0, new hamigaki::debug_num_put);
std::locale::global(loc);

のようにします。
グローバルロケールを参照して数値の入力が行われるとstd::cerrにメッセージが出力され、数値の出力が行われると数値とともにメッセージが出力されます。
もちろん、本当にロケールに依存した入出力を行いたい場合もメッセージが出力されてしまうわけですが、「うっかり」を見つけ出す役には立つのではないかと思います。