eao197 on the Web Сайт Евгения Охотникова |
[ Главная | Проекты | Описания | Об авторе | Лицензия ] |
C++ tricks: OPT_COUT
Время от времени приходится в некоторых кусках кода делать трасировочные печати (логирование). Но не всегда, а когда это разрешено. Например, какая-нибудь утилита выполняет свою работу тихо, ничего не отображая на стандартный поток вывода, если нет ошибок. Но вот этой утилите передают аргумент --verbose для того, чтобы она разсказывала о своих действиях. В этом случае тот же самый код должен перед каждым своим действием что-то сказать пользователю.
Раньше я делал приблизительно так: передавал в необходимые места указатель на std::ostream. Если этот указатель был не нулевой, значит трасировочная печать должна быть. Если же указатель нулевой, то делать ничего не нужно. Естественно, что перед каждым обращением к потоку требуется выполнить проверку:
void do_main_action( std::ostream * verbose_stream ) { if( verbose_stream ) *verbose_stream << "renaming files..." << std::endl; do_rename( verbose_stream ); if( verbose_stream ) *verbose_stream << "calculating..." << std::endl; do_calculation( verbose_stream ); if( verbose_stream ) *verbose_stream << "committing..." << std::endl; do_commit( verbose_stream ); }
Понятно, что писать if( verbose_stream ) в скором времени надоедает. Сразу хочется написать макрос VERBOSE_COUT:
#define VERBOSE_COUT(stream_ptr, what) if((stream_ptr)) *(stream_ptr) << what; void do_main_action( std::ostream * verbose_stream ) { VERBOSE_COUT( verbose_stream, "renaming files..." << std::endl ); do_rename( verbose_stream ); VERBOSE_COUT( verbose_stream, "calculating..." << std::endl ); do_calculation( verbose_stream ); VERBOSE_COUT( verbose_stream, "committing..." << std::endl ); do_commit( verbose_stream ); }
Вполне приемлимый способ. Если не считать, что из-за таких конструкций C++ и ругают. Фактически, макрос VERBOSE_COUT -- это надстройка над языком. И для ее понимания нужно будет разбираться с содержимым VERBOSE_COUT.
Но есть возможность создать макрос, который будет выглядеть как вызов функции, возвращающей std::ostream &:
#define OPT_COUT(stream_ptr) !(stream_ptr) ? std::cout : *(stream_ptr) void do_main_action( std::ostream * verbose_stream ) { OPT_COUT( verbose_stream ) << "renaming files..." << std::endl; do_rename( verbose_stream ); OPT_COUT( verbose_stream ) << "calculating..." << std::endl; do_calculation( verbose_stream ); OPT_COUT( verbose_stream ) << "committing..." << std::endl; do_commit( verbose_stream ); }
Фокус здесь в том, что код получается, практически, нормальный, без собственных расширений языка. Но печать осуществляется только, если verbose_stream отличен от нуля.
© 2003-2005 Е.А. Охотников
$LastChangedDate: 2005-04-29 08:42:34 +0400 (Пт, 29 апр 2005) $