Thursday, February 26, 2009

A C++ debug class

I finally got tired of commenting/uncommenting "cerr" and "cout" statements, and started to think about a simple debug helper class a few days ago. With this class, I need to archive:
1. An overall switch be should able to control the verbose level. This can be done through static class methods.
2. Can easily switch output from stderr to stdout, or a file. This can also be done with a static method.
3. The class should be able to track the execution of the code automatically, i.e. report when entering and exiting a function.
4. It should have an easy way of printing any variables in the code.
5. It can be easily plugged in existing code.
6. It has minimum impact on the performance of the code.

With these in mind, I come up with this Debug class:
1. The verbose level is from 0 (no debug output) to 5 (very verbose), with 1 being a special "trace only" level. In level 1, the class only report when entering and exiting a function.
2. To use it, one define a Debug object at the very beginning of a function. The constructor handles the "entering" trace, and the destructor handles the "exiting" trace.
3. The class provides many overloaded () operator to report any state variables. These methods return a reference to the debug object so that multiple debug entries can be stacked together:
  int test_func(){
Debug dbg("test_func");
...
dbg(2,a)(3,b)(5,c,d,e);
...
}
4. In addition to an overall verbose control, each individual object has an optional verbose level control as the second argument of the constructor.
5. The operator() methods, as well as the constructor and destructor, should be implemented as inline to improve performance.

Here is the interface of the class:
  class Debug{

public:

Debug(const string & trace_key, int verbose = -1);
~Debug();

// types with defined ostream<< operator
template <typename T>
Debug & operator()(int verbose, const T&);
template <typename T1, typename T2>
Debug & operator()(int verbose, const T1&, const T2&);
template <typename T1, typename T2, typename T3>
Debug & operator()(int verbose, const T1&, const T2&, const T3&);
template <typename T1, typename T2, typename T3, typename T4>
Debug & operator()(int verbose, const T1&, const T2&, const T3&, const T4&);
template <typename T1, typename T2, typename T3, typename T4, typename T5>
Debug & operator()(int verbose, const T1&, const T2&, const T3&, const T4&, const T5&);
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
Debug & operator()(int verbose, const T1&, const T2&, const T3&, const T4&, const T5&, const T6&);

// static methods to set the overall debug specs
static void set_verbose(int); // verbose level, default 0, no debug info will be printed
static void set_nesting_max(int); // maximum nesting level. default 8. no indent if set to 0
static void set_output(const string & filename, bool append=false); // output file
static void set_output(ostream &); // output stream, default clog

private:
...

};
 
Creative Commons License All contents on this page are licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.