Noticing this thread, I thought it would be interesting to start one on C++ techniques. Maybe a mod could make it a sticky, as well?
Here's the first installment: debugging macros. Very handy when you just want to see the name and value of a variable or expression. For convenience, they can be turned off by defining NDEBUG.
Code:
#ifndef BUG_HPP
#define BUG_HPP
/*
A simple set of macros for printing variable/expression text and values.
SBUG( stream, expression ) writes output to any std::ostream-like object.
BUG( expression ) writes output to std::cout.
If NDEBUG is defined, macros expand to nothing.
*/
#include <ostream> // for std::cout
#include <cctype> // for isdigit
namespace BUG_IMPL_ {
template < typename Stream, typename Type >
void print_dispatch( Stream& stream, char const* expression, Type const& value )
{
stream << "*** [" << __FILE__ << ", line #" << __LINE__ << "] ***\n";
/*
We'll flush the stream twice, just in case the outputting of 'value' should crash,
throw an exception, etc - at least we'll know what file/line we were at before the fact
*/
stream.flush( );
/*
Check if the expression was some sort of literal
*/
int
ch = expression[ 0 ];
if( !isalpha( ch ) && ch != '_' )
{
/*
If already quoted, output as is
*/
if( ch == '"' || ch == '\'' )
stream << " " << expression << "\n";
else
stream << " '" << expression << "'\n";
}
else
stream << " " << expression << " = '" << value << "'\n";
stream.flush( );
}
} // namespace BUG_IMPL_
#ifndef NDEBUG
#define SBUG( stream, expression ) BUG_IMPL_::print_dispatch( stream, #expression, expression );
#define BUG( expression ) SBUG( std::cout, expression )
#else
#define SBUG( stream, expression )
#define BUG( expression )
#endif // !NDEBUG
#endif // BUG_HPP
Example usage:
Code:
#include <iostream>
#include <cmath>
int main( void )
{
BUG( "entering main" );
int
a = 200;
float
b = 0.5;
char const*
c = "ten";
BUG( a );
BUG( b );
BUG( sqrt( a * b ) );
BUG( c );
BUG( "exiting main" );
}
Output:
*** [test.cpp, line #62] ***
"entering main"
*** [test.cpp, line #69] ***
a = '200'
*** [test.cpp, line #70] ***
b = '0.5'
*** [test.cpp, line #71] ***
sqrt( a * b ) = '10'
*** [test.cpp, line #72] ***
c = 'ten'
*** [test.cpp, line #73] ***
"exiting main"
And don't forget, they work with user-defined types, too:
Code:
#include <ostream>
#include <string>
using namespace
std;
struct name
{
name( string const& first, string const& last )
: first( first ), last( last )
{ }
friend ostream& operator << ( ostream& stream, name const& name )
{
return stream << name.last << ", " << name.first;
}
string
first,
last;
};
int main( void )
{
name
someone( "Sebastian", "Garth" );
BUG( someone );
}
Output:
*** [test.cpp, line #103] ***
someone = 'Garth, Sebastian'
Cheers!