Q: boost::format : can formatting variable arguments lists be done ?

Hello, Currently I have a piece of code that logs messages much in the same way as printf() : void MyLogger::dump( const std::string& format, va_list& list ) { const unsigned short buf_size = 1024; char buffer[ buf_size ]; ::memset( buffer, 0, buf_size ); ::_vsnprintf( buffer, buf_size - 1, format.c_str(), list); /.../ } After many headaches (and crashes) due to mistaken format specification fields, I thought to upgrade my class's API to use boost::format, but alas, I couldn't find the way to feed the format object from a va_list. Is there a way? thanks in advance... Dan.

Dan Dimerman wrote:
Currently I have a piece of code that logs messages much in the same way as printf() :
void MyLogger::dump( const std::string& format, va_list& list ) { const unsigned short buf_size = 1024; char buffer[ buf_size ]; ::memset( buffer, 0, buf_size ); ::_vsnprintf( buffer, buf_size - 1, format.c_str(), list);
/.../ }
After many headaches (and crashes) due to mistaken format specification fields, I thought to upgrade my class's API to use boost::format, but alas, I couldn't find the way to feed the format object from a va_list. Is there a way?
Why do you think that boost::format together with va_list will be any safer than vsnprintf? If boost::format accepted va_list, it would have to guess types from format string, which will be as dangerous as it is for vsnprintf. - Volodya

Vladimir is right. You've seen the problems and crashes that leaving type checking to the programmer causes. You need the compiler to do the checking for you. I suggest using the same kind of scheme as the iostreams library. You might want to do more design than this - but you could start by adding a small family of global functions that look like... (you'll have to work up any varargs support stuff - I don't remember it) MyLogger & operator << (MyLogger & logger, int i) { logger.dump("%d", i) ; } MyLogger & operator << (MyLogger & logger, char * str) { logger.dump("%s", str) ; } This will allow you to write... MyLogger Log .... Int I ; Log << 10 << "abc" << I ; ...it will be (mostly) type safe - the type dangerous stuff is isolated to one place per output type - and you can extend it as you go. You'll likely need extra formatting stuff and that's where boost::format may help you. HTH - Richard -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Vladimir Prus Sent: 22 December 2004 10:45 To: boost-users@lists.boost.org Subject: [Boost-users] Re: Q: boost::format : can formatting variablearguments lists be done ? Dan Dimerman wrote:
Currently I have a piece of code that logs messages much in the same way as printf() :
void MyLogger::dump( const std::string& format, va_list& list ) { const unsigned short buf_size = 1024; char buffer[ buf_size ]; ::memset( buffer, 0, buf_size ); ::_vsnprintf( buffer, buf_size - 1, format.c_str(), list);
/.../ }
After many headaches (and crashes) due to mistaken format specification fields, I thought to upgrade my class's API to use boost::format, but alas, I couldn't find the way to feed the format object from a va_list. Is there a way?
Why do you think that boost::format together with va_list will be any safer than vsnprintf? If boost::format accepted va_list, it would have to guess types from format string, which will be as dangerous as it is for vsnprintf. - Volodya _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users -- No virus found in this incoming message. Checked by AVG Anti-Virus. Version: 7.0.296 / Virus Database: 265.6.3 - Release Date: 21/12/2004 -- No virus found in this outgoing message. Checked by AVG Anti-Virus. Version: 7.0.296 / Virus Database: 265.6.3 - Release Date: 21/12/2004

Richard Howells wrote:
Vladimir is right.
You've seen the problems and crashes that leaving type checking to the programmer causes. You need the compiler to do the checking for you.
I suggest using the same kind of scheme as the iostreams library. You might /.../ ...it will be (mostly) type safe - the type dangerous stuff is isolated to one place per output type - and you can extend it as you go. You'll likely need extra formatting stuff and that's where boost::format may help you.
I was thinking about something like: MyLogger::print( const boost::format& f ) and since all format's operator %() return a boost::format, I could with this single function reap all the types handled by it at once. I use a function rather than the operator << because they are actually template functions, with the parameter being the severity. So for _DEBUG versions, the MyLogger::print< DBG >() function instantiates to a proper call to print, while in _RELEASE versions it instantiates to an empty function. I just didn't see a clean way to do this with operators. Dan

Vladimir is right.
You've seen the problems and crashes that leaving type checking to the programmer causes. You need the compiler to do the checking for you.
I suggest using the same kind of scheme as the iostreams library. You might /.../ ...it will be (mostly) type safe - the type dangerous stuff is isolated to one place per output type - and you can extend it as you go. You'll
Well it might be crude but sometimes the pre-processor is your friend... template<class T> MyLogger & operator<<(MyLogger & log, T o) { #if defined(_DEBUG) // code goes here #else // leave empty #endif } ...but your problem is still there because you don’t know what to put in 'code goes here'. I think you still need a family of strongly typed MyLogger::print overloads to call there. HTH - Richard -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Dan Dimerman Sent: 22 December 2004 13:03 To: boost-users@lists.boost.org Subject: [Boost-users] Re: Q: boost::format : can formatting variablearguments lists be done ? Richard Howells wrote: likely
need extra formatting stuff and that's where boost::format may help you.
I was thinking about something like: MyLogger::print( const boost::format& f ) and since all format's operator %() return a boost::format, I could with this single function reap all the types handled by it at once. I use a function rather than the operator << because they are actually template functions, with the parameter being the severity. So for _DEBUG versions, the MyLogger::print< DBG >() function instantiates to a proper call to print, while in _RELEASE versions it instantiates to an empty function. I just didn't see a clean way to do this with operators. Dan _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users -- No virus found in this incoming message. Checked by AVG Anti-Virus. Version: 7.0.296 / Virus Database: 265.6.3 - Release Date: 21/12/2004 -- No virus found in this outgoing message. Checked by AVG Anti-Virus. Version: 7.0.296 / Virus Database: 265.6.3 - Release Date: 21/12/2004

Richard Howells wrote:
Well it might be crude but sometimes the pre-processor is your friend...
template<class T> MyLogger & operator<<(MyLogger & log, T o) { #if defined(_DEBUG) // code goes here #else // leave empty #endif }
...but your problem is still there because you don’t know what to put in 'code goes here'. I think you still need a family of strongly typed MyLogger::print overloads to call there.
That would be the easy part. It becomes trickier, when you want to specify a logging severity level, such as in: the_logger.printf< Log::DBG >( "some message %d.", 42 ); you may want to use manipulators, as in: the_logger << Log::dbg << "some message" << 42; but then again, when using operator<<, you have no guarantees of what happens if several threads are writing to the same logger. Then you may get mixed/mangled messages. To fix this you may want to use a "flush" manipulator, but (to my taste) at that level the complexity of the operator approach defeats its purpose, i.e. simplicity and elegance. Dan
participants (3)
-
Dan Dimerman
-
Richard Howells
-
Vladimir Prus