在我们的项目中,我们使用 printf 兼容函数将消息添加到外部日志文件。例如我们可以写
__LOG_INFO( "number of files = %d\n", number_of_files );
__LOG_INFO( "Just for information\n" );
的函数声明__LOG_INFO
如下所示
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 ) );
}
...
我们现在想使用 C++ 11 constexpr 功能添加一些简单的编译时格式字符串检查,例如,对格式字符串中的参数数量进行非常简单的检查,我们有这个函数
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 );
}
现在的问题是我们不能在__LOG_INFO
函数内部添加类似 static_assert 的东西,因为编译器抱怨 fmt 不是一个整数常量。所以现在我们有这个丑陋的宏解决方案:
#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__); \
}
因此,与其打电话__LOG_INFO
,不如打电话LOG_INFO
。
除了使用上面的那些宏之外,还有没有更好的解决方案?