In our project we use a printf compatible function to add messages to an external log file. e.g. We can write
__LOG_INFO( "number of files = %d\n", number_of_files );
__LOG_INFO( "Just for information\n" );
The function declarations of __LOG_INFO
look like this
template<int N>
inline void __LOG_INFO( const char (&fmt)[N] )
{
call_printf( MODULE_NAME, fmt, debug_parameters() );
}
template<int N, typename T1>
static void __LOG_INFO( const char (&fmt)[N], const T1 &t1 )
{
call_printf( MODULE_NAME, fmt, debug_parameters( t1 ) );
}
template<int N, typename T1, typename T2>
static void __LOG_INFO( const char (&fmt)[N], const T1 &t1, const T2 &t2 )
{
call_printf( MODULE_NAME, fmt, debug_parameters( t1, t2 ) );
}
...
We now would like to add some simple compile time format string checking using the C++ 11 constexpr functionality, e.g. to do a very simple checking of the number of parameters in the format string we have this function
template<int N>
constexpr static int count_arguments( const char (&fmt)[N], int pos = 0, int num_arguments = 0 )
{
return pos >= N-2 ? num_arguments :
fmt[pos] == '%' && fmt[pos+1] != '%' ? count_arguments( fmt, pos+1, num_arguments+1 ) :
count_arguments( fmt, pos+1, num_arguments );
}
The problem now is that we cannot add something like static_assert inside the __LOG_INFO
functions themselves, since the compiler complains that fmt is not an integral constant. So right now we have this ugly macro solution:
#define COUNT_ARGS(...) COUNT_ARGS_(,##__VA_ARGS__,8,7,6,5,4,3,2,1,0)
#define COUNT_ARGS_(z,a,b,c,d,e,f,g,h,cnt,...) cnt
#define LOG_INFO(a, ...) \
{ \
static_assert( count_arguments(a)==COUNT_ARGS(__VA_ARGS__), "wrong number of arguments in format string" ); \
__LOG_INFO(a,##__VA_ARGS__); \
}
So instead of calling __LOG_INFO
, one has to call LOG_INFO
.
Is there any better solution besides using those macros above?