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) $
e-mail

Hosted by uCoz