NF

地方で働くプログラマ

12回目:デバッグ文

デバッグマクロについて。
printfデバッグをするために様々なマクロが書かれてると思います。仕事でも、個々人が自分のデバッグスニペットを持ち運んでたり、プロジェクトによっては予め準備してデバッグビルド時だけ有効にしたり、でも使い方が分からない人が自分で作り始めたり、引数や型毎の大量のマクロがあったり、色々見た事あります。
ちなみに、誰かが埋め込んだデバッグ文の削除漏れでサービスダウンするというのが最近隣の部署でありました。前述のプロジェクトで統率取っておくとこういうの減るかもしれませんね。


本題です。
簡潔で利用範囲の広いデバッグプリントってどういうのだろ、と思って競プロで有名なtouristさんのコードを見ていたら、以下のコードが定義してありました。他の人のコードでも結構同じようなのが使われえるようでした。

#include <iostream>
using namespace std;

void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}

#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

int main()
{
    int i = 10;
    float f = 3.14;
    bool b = true;
    debug(i, f, b);
}

ビルド・実行結果

# g++ -Wall -std=c++14 -O2 -o a.out source_file.cpp -DLOCAL
# ./a.out
[i, f, b]: 10 3.140000 1


手元のビルド時だけ「-DLOCAL」を付けておくと、提出した後はelseの方が実行されて消えるという仕組みですね。CodeforcesとかAtCoderでは「ONLINE_JUDGE」というマクロが定義されているようで、#ifndef ONLINE_JUDGE としておけば、手元だけ使えるようになるんですね。
組み込み型なら、型と個数を気にせずに出力できます。debug_out(Head H, Tail... T)が1引数ごとに再帰的に呼ばれてる感じですかね?debugマクロを噛んでるのは引数名を出力してるだけで、値だけなら直接debug_out読んでも同じっぽいです。
 
参考にしたコードではもう少し拡張されてるので、次の記事で記載します。