stinos
26th November 2008, 15:58
Hi,
I'm not too keen on variable argument lists, but I'd like to use them for some logging functions.
Suppose the prototype for logging functions is
void Log( const String& sMessage, const int iLevel, const bool bUseLineEnd );
String already takes variable argument lists in it's sPrintf function, which also returns a reference to this, so I could use
Log( String().sPrintf( "test %d", 5 ), level, true ); for example.
That's not really a problem, but what happens: String is constructed, then allocates memory, then calls sprintf and returns a reference to itself. Internally, Log copies the memory from String into pre-allocated space. The call returns, and String and it's memory are deallocated.
What I would rather like to see, is that the sprintf call happens directly on the pre-allocated memory in Log. That saves allocating, memcpy and deallocation. However, I would also like to keep the same prototype, so that I can use Log( "test %d", 5, level, true );
Variable arguments can't be listed first, so my first thought was to simply declare all possible functions:
template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const bool bLineEnd );
template< class T0, class T1 >
void Log( const char* Format, const T0 arg0, const T1 arg1, const int iLevel, const bool bLineEnd );
and so on.
Implementating this was easy at first sight: let the Logger class have a method that accepts a va_list and construct the list from the arguments.
template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const bool bLineEnd )
{
va_list args;
va_start( args, Format );
InternalLogFunction( Format, args, iLevel, bLineEnd );
va_end( args );
}
This does excatly what I want, though it's not overly pretty, but gcc (4.1.2) chokes on this saying "va_start used in function with fixed args".
I don't really understand why it is not allowed (afaik va_start just lets args point to the next element on the stack, arg0 in this case), can someone explain this?
Also, what would be other ways to achieve this? What I basically want is a variable argument list of some kind, followed by 2 named parameters. (ok I could just use Log( const int, const bool, const char*, ... ) but it would just make writing much easier if it behaved like the non-printf Log)
Thanks!
I'm not too keen on variable argument lists, but I'd like to use them for some logging functions.
Suppose the prototype for logging functions is
void Log( const String& sMessage, const int iLevel, const bool bUseLineEnd );
String already takes variable argument lists in it's sPrintf function, which also returns a reference to this, so I could use
Log( String().sPrintf( "test %d", 5 ), level, true ); for example.
That's not really a problem, but what happens: String is constructed, then allocates memory, then calls sprintf and returns a reference to itself. Internally, Log copies the memory from String into pre-allocated space. The call returns, and String and it's memory are deallocated.
What I would rather like to see, is that the sprintf call happens directly on the pre-allocated memory in Log. That saves allocating, memcpy and deallocation. However, I would also like to keep the same prototype, so that I can use Log( "test %d", 5, level, true );
Variable arguments can't be listed first, so my first thought was to simply declare all possible functions:
template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const bool bLineEnd );
template< class T0, class T1 >
void Log( const char* Format, const T0 arg0, const T1 arg1, const int iLevel, const bool bLineEnd );
and so on.
Implementating this was easy at first sight: let the Logger class have a method that accepts a va_list and construct the list from the arguments.
template< class T0 >
void Log( const char* Format, const T0 arg0, const int iLevel, const bool bLineEnd )
{
va_list args;
va_start( args, Format );
InternalLogFunction( Format, args, iLevel, bLineEnd );
va_end( args );
}
This does excatly what I want, though it's not overly pretty, but gcc (4.1.2) chokes on this saying "va_start used in function with fixed args".
I don't really understand why it is not allowed (afaik va_start just lets args point to the next element on the stack, arg0 in this case), can someone explain this?
Also, what would be other ways to achieve this? What I basically want is a variable argument list of some kind, followed by 2 named parameters. (ok I could just use Log( const int, const bool, const char*, ... ) but it would just make writing much easier if it behaved like the non-printf Log)
Thanks!