Qualified's blog

By Qualified, history, 4 years ago, In English

My debugging template is:

#define ts to_string
string ts(char c) { return string(1, c); }
string ts(bool b) { return b ? "true" : "false"; }
string ts(const char* s) { return (string)s; }
string ts(string s) { return s; }
template<class A> string ts(complex<A> c) { 
	stringstream ss; ss << c; return ss.str(); }
string ts(vector<bool> v) { 
	string res = "{"; for(int i = 0; i < si(v); ++i) res += char('0' + v[i]);
	res += "}"; return res; }
template<size_t SZ> string ts(bitset<SZ> b) {
	string res = ""; for(int i = 0; i < SZ; ++i) res += char('0' + b[i]);
	return res; }
template<class A, class B> string ts(pair<A,B> p);
template<class T> string ts(T v) {
	bool fst = 1; string res = "{";
	for (const auto& x: v) {
		if (!fst) res += ", ";
		fst = 0; res += ts(x);
	}
	res += "}"; return res;
}
template<class A, class B> string ts(pair<A,B> p) {
	return "(" + ts(p.f) + ", " + ts(p.s) + ")"; }

void DBG() { cerr << "]" << endl; }
template<class H, class... T> void DBG(H h, T... t) {
	cerr << ts(h); if (sizeof...(t)) cerr << ", ";
	DBG(t...); }
#ifdef LOCAL
#define dbg(...) cerr << "[" << #__VA_ARGS__ << "]: [", DBG(__VA_ARGS__)
#else
#define dbg(...) 0
#endif

When I type

dbg(a, n)

where 'a' is the vector name and n is the size of the vector. 'a' contains the following {1, 2, 3, 4, 5} and n = 5

it prints

[a, n]: [{1, 2, 3, 4, 5}, 5]

but I want it to print

[a]: [{1, 2, 3, 4, 5}]
[n]: [5]

without having to type

dbg(a);
dbg(n);

Is there any way to do this?

  • Vote: I like it
  • +3
  • Vote: I do not like it

| Write comment?
»
4 years ago, # |
Rev. 5   Vote: I like it 0 Vote: I do not like it

Here is code that does what you want. DBG takes a string with the names separated by commas as the first parameter, and the variables as the remaining parameters. Then it prints the first name and the first variables, and passes the rest recursively to DBG.

void DBG(string names) {}
template<class H, class... T> void DBG(string names, H h, T... t) {
	auto pos = names.find(',');
	auto first_name = names.substr(0, pos);
	auto rest = names.substr(pos+1);
	// Strip space at the beginning
	while(rest.front() == ' '){
		rest = rest.substr(1);
	}
	cerr << "["<<first_name<<"] ["<<ts(h)<<"]"<<endl;
	DBG(rest, t...);
}
#ifdef LOCAL
#define dbg(...) DBG(#__VA_ARGS__, __VA_ARGS__)
#else
#define dbg(...) 0
#endif
  • »
    »
    4 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    What am I supposed to put in the function DBG?

    • »
      »
      »
      4 years ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      DBG takes the comma separated names of the variables, and then the variables as parameters.

      You just need to replace this part of your code with the code I gave.

      • »
        »
        »
        »
        4 years ago, # ^ |
          Vote: I like it 0 Vote: I do not like it

        Thanks! This is the new code that I am working with:

        Code

        dbg converts dbg(a, n); to dbg(a); dbg(n); edbg doesn't change dbg(a, n)

»
4 years ago, # |
  Vote: I like it 0 Vote: I do not like it

I use the following macros if need debugging:

#define INFO1(x)                #x << ": " << (x)
#define INFO2(x, ...)           INFO1(x) << ", " << INFO1(__VA_ARGS__)
#define INFO3(x, ...)           INFO1(x) << ", " << INFO2(__VA_ARGS__)
#define INFO4(x, ...)           INFO1(x) << ", " << INFO3(__VA_ARGS__)

#define SELECT(_1, _2, _3, _4, X, ...)  X

#define DUMP(...)               SELECT(__VA_ARGS__, INFO4, INFO3, INFO2, INFO1)(__VA_ARGS__)
#define TRACE(...)              do { std::clog << DUMP(__VA_ARGS__) << '\n'; } while (false)

Sample usage:

int x = -1, y =  2, z = -3;
TRACE(x, y, z);

Output: x: -1, y: 2, z: -3

All you need is to overload the stream output operators for vector<>, pair<>, etc. as you want to.