1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

自作デバッグ関数の覚書き

Last updated at Posted at 2020-06-11

プログラム書いていて、途中結果を出力したいときってありますよね。

デバッガよくわかんないので途中出力しています。うんうん。

多分ところどころガバがあります。

今まで

こんな感じでやってました

#include <bits/stdc++.h>
using namespace std;

#define debug(x) cout<<#x<<" = "<<(x)<<endl
#define debug2(x,y) cout<<"("<<#x<<","<<#y<<") = ("<<(x)<<","<<(y)<<")"<<endl
#define debug3(x,y,z) cout<<"("<<#x<<","<<#y<<","<<#z<<") = ("<<(x)<<","<<(y)<<","<<(z)<<")"<<endl

int main(){
  int a = 10;
  double b = 3.14;
  string c = "hoge";

  debug(a);
  debug2(a,b);
  debug3(a,b,c);
}

出力はこんな感じ

a = 10
(a,b) = (10,3.14)
(a,b,c) = (10,3.14,hoge)

ここで使っているのが、「文字列化演算子」#です。変数の名前自体を文字列に変換して出力できるので、どの変数がどの値なのかわかりやすいです。

可変引数テンプレート

ただ、変数の数ごとに使い分けをしているのがアホらしいですね。ここで、どこかで小耳に挟んだ「可変引数テンプレート」を使います。

パラメータパックを最初の要素から順番に処理していきたい場合には、「任意の型のパラメータをひとつと、任意の個数の任意の型のパラメータを受け取る」というような形式のパラメータリストとし、再帰によって処理をする:
https://cpprefjp.github.io/lang/cpp11/variadic_templates.html

とのことなのでそこに書いてあるのをほぼコピペして書きます。

void debug(){cout<<endl;} //引数がなくなったときのためのdebug()

template <class H, class... Ts>
void debug(H&& h, Ts&&... ts){
  cout<<h<<" ";
  debug(forward<Ts>(ts)...);
}
int main(){
  int a = 10;
  double b = 3.14;
  string c = "hoge";

  debug(a); //10
  debug(a,b); //10 3.14
  debug(a,b,c); //10 3.14 hoge
}

右辺値参照&&とかfoward()とかは、よくわかんなかったけど動くからええかって…………(一応参考: https://cpprefjp.github.io/reference/utility/forward.html , https://cpprefjp.github.io/lang/cpp11/rvalue_ref_and_move_semantics.html

テンプレートで対応

pair

このままだとpairを出力できないので、cout<<h<<" ";のところをテンプレートで書き換えます

template <class T>
void show(T &x){cout<<x<<" ";}

template <class P, class Q>
void show(pair<P, Q> &x){
  cout<<"("<<x.first<<", "<<x.second<<") ";
}

void debug(){cout<<endl;} //引数がなくなったときのためのdebug()

template <class H, class... Ts>
void debug(H&& h, Ts&&... ts){
  show(h);
  debug(forward<Ts>(ts)...);
}
int main(){
  int a = 10;
  double b = 3.14;
  string c = "hoge";

  debug(make_pair(a,b)); //(10, 3.14)
  debug(make_pair(b,c)); //(3.14, hoge)
}

vector

vectorを突っ込んで出力したいので。

template <class T>
void debug(vector<T> &vt){
  for(auto x: vt){show(x);}cout<<endl;
}
int main(){
  vector<int> vi = {1,2,3,4,5};
  debug(vi); //1 2 3 4 5
}

初期化子リスト

debug({1, 3, 5});ってやりたいなって(でもこれ型合わせなきゃいけないとかであんまりデバッグ的に意味はない。{}に入れなくて良いじゃん)。

template <class T>
void debug(initializer_list<T> init){
  for(auto x: init){show(x);}cout<<endl;
}
int main(){
  debug({1,3,5}); //1 3 5
}

行番号出したい

どこでバグってるか多少わかりやすくするために行番号を出力するようにします。

#define ldebug(...) do{cout<<"["<<setw(3)<<__LINE__<<"] "; debug(__VA_ARGS__);}while(0)
  • マクロの引数(...)は可変引数マクロで、マクロ内では__VA_ARGS__の位置に展開されます。
  • __LINE__はプリプロセッサの段階で行数に置換されます。
  • setw(3)coutの書式設定で、printf("%3d")に対応しています。
  • do-while文にしているのは、マクロで複文を書くときの常套手段です

やっぱり変数名も出したい

最初に書いたみたいに変数名表示したいですよね。ええ。

#define DEBUG(...) do{cout<<#__VA_ARGS__<<" = "; debug(__VA_ARGS__);}while(0)
  • 先ほどの__VA_ARGS__に、冒頭で紹介した「文字列化演算子」#を合わせます

行番号も変数名も出したい

欲張り。

#define lDEBUG(...) do{cout<<"["<<setw(3)<<__LINE__<<"] "<<#__VA_ARGS__<<" = "; debug(__VA_ARGS__);}while(0)

まとめ

今までのをまとめました

#include <bits/stdc++.h>
using namespace std;

namespace /* debug */{
  #define DEBUG(...) do{cout<<#__VA_ARGS__<<" = ";  debug(__VA_ARGS__);}while(0) //変数
  #define ldebug(...) do{cout<<"["<<setw(3)<<__LINE__<<"] "; debug(__VA_ARGS__);}while(0) //行数
  #define lDEBUG(...) do{cout<<"["<<setw(3)<<__LINE__<<"] "<<#__VA_ARGS__<<" = ";  debug(__VA_ARGS__);}while(0) //変数, 行数

  template <class T>
  void show(T &x){cout<<x<<" ";}

  template <class P, class Q>
  void show(pair<P, Q> &x){
    cout<<"("<<x.first<<", "<<x.second<<") ";
  }

  void debug(){cout<<endl;} //引数がなくなったときのためのdebug()

  template <class H, class... Ts>
  void debug(H&& h, Ts&&... ts){
    show(h);
    debug(forward<Ts>(ts)...);
  }

  template <class T>
  void debug(vector<T> &vt){
    for(auto x: vt)show(x);
    cout<<endl;
  }

  template <class T>
  void debug(initializer_list<T> init){
    for(auto x: init)show(x);
    cout<<endl;
  }
}

int main(){
  int a=1, b=10, c=-1;
  double d=3.14, e=1.41;
  string S = "hoge";

  debug(a);
  DEBUG(99);
  ldebug(d);
  lDEBUG(S);

  cout<<"//////////"<<endl;

  debug(a,b,c);
  DEBUG(d,e,S);
  ldebug(a,d,S);
  lDEBUG(b,c,e,"fuga");

  cout<<"//////////"<<endl;

  debug({a,b,c});
  DEBUG({d,e,1.23});
  ldebug({a,b,99});
  lDEBUG({"piyo","nyo"});

  cout<<"//////////"<<endl;

  vector<pair<int, double>> pid = {{a,d}, {c,e}};
  debug(pid);
  DEBUG(pid);
  ldebug(pid);
  lDEBUG(pid);
}
output.txt
1 
99 = 99 
[ 45] 3.14 
[ 46] S = hoge 
//////////
1 10 -1 
d,e,S = 3.14 1.41 hoge 
[ 52] 1 3.14 hoge 
[ 53] b,c,e,"fuga" = 10 -1 1.41 fuga 
//////////
1 10 -1 
{d,e,1.23} = 3.14 1.41 1.23 
[ 59] 1 10 99 
[ 60] {"piyo","nyo"} = piyo nyo 
//////////
(1, 3.14) (-1, 1.41) 
pid = (1, 3.14) (-1, 1.41) 
[ 67] (1, 3.14) (-1, 1.41) 
[ 68] pid = (1, 3.14) (-1, 1.41) 

まともな使用例

/* debugのアレコレ */

int main(){
  for(int i=1; i<=3; i++){
    for(int j=4; j<=6; j++){
      DEBUG(i,j,i+j,i*j);
    }
  }
}
i,j,i+j,i*j = 1 4 5 4 
i,j,i+j,i*j = 1 5 6 5 
i,j,i+j,i*j = 1 6 7 6 
i,j,i+j,i*j = 2 4 6 8 
i,j,i+j,i*j = 2 5 7 10 
i,j,i+j,i*j = 2 6 8 12 
i,j,i+j,i*j = 3 4 7 12 
i,j,i+j,i*j = 3 5 8 15 
i,j,i+j,i*j = 3 6 9 18 

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?