Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 06:50
Оценка:
Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.

1) Сначала я хотел сделать это через функцию которая вызывает и fprint и printf, но обнаружил что чтобы это сделать необходимо определить число передаваемых параметров и их типы по строке форматирования... в итоге был напсин код на асме который успешно сохраняет кусочек стека в heapе а потом шаманит с указателем стека и вызывает printf и fprint. Все бы нечиго, я даже заделал макрос, который генерит соответсвующие asmные вставки, но по каким то причинам слово Assembler кроме меня никому не греет душу

2) Возникла идея, что раз нельзя что бы функция ето все тварила, то пусть хотя бы макрос, что ему стоит строчке в тексте слепить, но обнаружилось что препроцессор C++ такой ущербный язык, что кажется его таким сделал специально — 'ибо нефиг' . В результате нескольких попыток, был получен слегка корявый вариант, который все таки слепляет агрументы из двух списков для функции с переменным числом агрументов:

// Бубен :)
#define __AST *
#define Cc __AST/  //Comment Close
#define Co /__AST  //Comment Open
#define _FUNCCALL(func, h, t) func(Co h Cc, Co t Cc)
// Конец Бубна

// Целывой макрос
FILE* logFile = 0;
#define LOGPRINT(x) \
   printf##x; \
   if (logFile) _FUNCCALL(fprintf, (Cc logFile Co), x);

// Используется как
LOGPRINT((Cc "Error code: %d. Error Message: %s\r\n", errCode, errMsg Co))


ВОПРОС: Есть у кого идеи как всетаки сделать макрос LOGPRINT чтобы его можно было записать:
LOGPRINT(("Error code: %d. Error Message: %s\r\n", errCode, errMsg)), т.е. без Cc и Co.
а то не красиво смотрится

Кто подскажеть тому



18.08.05 11:38: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
Re: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 06:53
Оценка:
Сори! Обшибся набирая..

Правильный тескт макроса

// Целывой макрос
FILE* logFile = 0;
#define LOGPRINT(x) \
   printf( Co x Cc ); \       // здесь было printf##x
   if (logFile) _FUNCCALL(fprintf, (Cc logFile Co), x);
Re: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:09
Оценка:
Здравствуйте, vnechiporenko, Вы писали:


V>Кто подскажеть тому


Напиши свою функцию с параметром-строкй и переменным числом аргументов, которая будет вызывать vfprintf.
Далее стандартно...

#ifdef _DEBUG
#define LOGPRINT myFunc
#else
#define LOGPRINT 1 ? (void)0 : myFunc
#endif

LOGPRINT("Error code: %d. Error Message: %s\r\n", errCode, errMsg);
Имею скафандр — готов путешествовать!
Re[2]: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 07:33
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Здравствуйте, vnechiporenko, Вы писали:



V>>Кто подскажеть тому


RB>Напиши свою функцию с параметром-строкй и переменным числом аргументов, которая будет вызывать vfprintf.

RB>Далее стандартно...

RB>#ifdef _DEBUG

RB> #define LOGPRINT myFunc
RB>#else
RB> #define LOGPRINT 1 ? (void)0 : myFunc
RB>#endif

RB>LOGPRINT("Error code: %d. Error Message: %s\r\n", errCode, errMsg);


Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .
Re[3]: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:39
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V> Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .


Ты пишешь под абстрактного коня в вакууме, или под конкретную систему?
Имею скафандр — готов путешествовать!
Re[3]: Препроцессор и переменное число аргументов
От: rus blood Россия  
Дата: 18.08.05 07:42
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V> Текст myFunc попробуй написать и увидишь что не сможешь определить количетсво переданных параметров и их типы (Ну если конечно не писать свой анализатор строки форматирование -- нормальному человеку это делать лень), а как следствие не сможешь их ретранслировать в fprintf. Ну к твоему облегчению я писал уже такую функцию, в ней я использовал вставки на asm'е.. (смотри (1) в моем первом посте). Если вкурсе как написать это без асма то получить много .


Впрочем, неважно.

1. Функции типа vfprintf используют va_list для просмотра аргументов.

2. Если подобных функций нет, можно взять готовый код разбора аргументов. Смотри ATLString или MFC CString::Format
Имею скафандр — готов путешествовать!
Re[3]: Препроцессор и переменное число аргументов
От: Аноним  
Дата: 18.08.05 07:51
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

в принципе ссылка уже дана, но на всякий случай
кому лень искать, должно быть примерно так
void Trace( const char *szFormat, ... )
{
va_list arg;
va_start( arg, szFormat ); // Initialize variable arguments
char sMessage[ 1024 ] = { '\0' };
::vsprintf( sMessage, szFormat, arg );
va_end( arg ); // Reset variable arguments
::strcat( sMessage, "\r\n" );

// далее sMessage в файл
}
Re[4]: Препроцессор и переменное число аргументов
От: vnechiporenko  
Дата: 18.08.05 08:02
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>1. Функции типа vfprintf используют va_list для просмотра аргументов.

Сори ступил Я только сейчас прочел про vfprintf (не знал о ё суфществовании), действительно рулит... Её спецом похоже для этих целей сделали.

RB>2. Если подобных функций нет, можно взять готовый код разбора аргументов. Смотри ATLString или MFC CString::Format

Угу.. и это дельный совет

Thanks,
Re: Препроцессор и переменное число аргументов
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 18.08.05 10:30
Оценка: 3 (1)
Здравствуйте, vnechiporenko, Вы писали:

V>Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.


V>ВОПРОС: Есть у кого идеи как всетаки сделать макрос LOGPRINT чтобы его можно было записать:

V>LOGPRINT(("Error code: %d. Error Message: %s\r\n", errCode, errMsg)), т.е. без Cc и Co.
V>а то не красиво смотрится

В библиотеке ACE это уже давно сделано. Вот пример логирования из их Basic_Types_Test.cpp:
ACE_ERROR ((LM_ERROR, ACE_TEXT ("assertion failed \"%s\": %u != %u\n"),
                        message, i, j));


Вот здесь можно посмотреть, как это сделано: http://www.dre.vanderbilt.edu/Doxygen/Stable/ace/Log__Msg_8h.html#a4
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 18.08.05 11:14
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V>Сори ступил


Ничего страшного Ты не один.
Я тоже не знал о ее существовании, и тоже хотел логирование с форматной строкой сделать, как в printf. А выкрутился установкой исходника MS CRT и компиляцией модифицированной CRT! Был жутко доволен своей изобретательностью, пока не узнал про vprintf
Re: Препроцессор и переменное число аргументов
От: pavel_turbin  
Дата: 18.08.05 11:15
Оценка:
вроде бы в Linux-e (gcc?) такой наворот есть.
Re[4]: Препроцессор и переменное число аргументов
От: degor Россия  
Дата: 18.08.05 11:21
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Ты пишешь под абстрактного коня в вакууме, или под конкретную систему?

сферического коня в вакууме
Re[2]: Препроцессор и переменное число аргументов
От: arcman Россия  
Дата: 19.08.05 13:11
Оценка:
Здравствуйте, pavel_turbin, Вы писали:

_>вроде бы в Linux-e (gcc?) такой наворот есть.

Не только есть, но и прекрасно используется
Макрос с переменным числом параметров — почти как функция.
Удобно — жуть как, незаменим для дебуга
Re: Препроцессор и переменное число аргументов
От: WinterMute Россия http://yarrr.ru
Дата: 19.08.05 15:07
Оценка: 2 (1) +1
IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:

class LogOutput
{
   ...
};
LogOutput log_print;

log_print << "text: " << 5;
Re[3]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 19.08.05 16:29
Оценка:
Здравствуйте, arcman, Вы писали:

A>Не только есть, но и прекрасно используется

A>Макрос с переменным числом параметров — почти как функция.
A>Удобно — жуть как, незаменим для дебуга

Слушай, расскажи поподробнее?
Re[2]: Препроцессор и переменное число аргументов
От: Сергей  
Дата: 19.08.05 16:32
Оценка:
Здравствуйте, WinterMute, Вы писали:

WM>IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:


WM>
WM>class LogOutput
WM>{
WM>   ...
WM>};
WM>LogOutput log_print;

WM>log_print << "text: " << 5;
WM>


Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?
И под C не покатит, так что может оно и лучше, но не так универсально.
Re[3]: Препроцессор и переменное число аргументов
От: Centaur Россия  
Дата: 20.08.05 02:37
Оценка:
Здравствуйте, Сергей, Вы писали:

WM>>IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:


WM>>
WM>>log_print << "text: " << 5;
WM>>


С>Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?


class null_ostream
{
public:
  template <typename T>
  null_ostream& operator<<(const T&) const
  {}
};

#ifdef WITH_LOGGING
log_ostream log_print;
#else
null_ostream log_print;
#endif

Дальше, оптимизирующий компилятор все обращения к log_print в нелогирующей версии выоптимизирует до нуля.
Re: Препроцессор и переменное число аргументов
От: vdimas Россия  
Дата: 20.08.05 07:28
Оценка:
Здравствуйте, vnechiporenko, Вы писали:

V>Суть проблеммы вначале заключалась в том что бы писать форматированный вывод printfа помимо как в OUTPUT еще и в лог файл.


[...]
V>Кто подскажеть тому

А почему бы не сделать шаблонные заготовки ф-ий, до, скажем, 15-20 аргументов.

типа:
#ifdef DEBUG
#    define LOGPRINT_FUNC printf
#else
#    define LOGPRINT_FUNC empty_func
inline void empty_func(...) {}
#endif

template<typename T1>
inline LOGPRINT(T1 t1) {
    LOGPRINT_FUNC(t1);
}

template<typename T1, typename T2>
inline LOGPRINT(T1 t1, T2 t2) {
    LOGPRINT_FUNC(t1, t2);
}

// и т.д.


empty_func(...) — пустая, будет "проглочена" компилятором в релизе.
Re[3]: Препроцессор и переменное число аргументов
От: pavel_turbin  
Дата: 21.08.05 10:30
Оценка:
Здравствуйте, arcman, Вы писали:

A>Здравствуйте, pavel_turbin, Вы писали:


_>>вроде бы в Linux-e (gcc?) такой наворот есть.

A>Не только есть, но и прекрасно используется
A>Макрос с переменным числом параметров — почти как функция.
A>Удобно — жуть как, незаменим для дебуга

что делает код непортируемый в Windows, т.к. cl не имеет такой поддержки.
Re[4]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 08:19
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Дальше, оптимизирующий компилятор все обращения к log_print в нелогирующей версии выоптимизирует до нуля.

Не факт.
Боюсь, оптимизатор может не справиться с таким случаем (для этого компилятору пришлось бы доказать, что ни одна из non_inline_functionX не имеет побочных эффектов; может быть, что глобальная оптимизация с этим и справится, но гарантии нет):
null_stream() << non_inline_function1() + non_inline_function2()/non_inline_function3();
Re[3]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 08:24
Оценка: 3 (1)
Здравствуйте, Сергей, Вы писали:

С>Здравствуйте, WinterMute, Вы писали:


WM>>IMHO, лучше пользоватся потоками. Определи что-нибудь вроде такого:


WM>>
WM>>class LogOutput
WM>>{
WM>>   ...
WM>>};
WM>>LogOutput log_print;

WM>>log_print << "text: " << 5;
WM>>


С>Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?


Тут тоже макросами можно.

#ifdef DEBUG
#define TRACE(x) get_trace_stream()<<x
#else
define TRACE(x)
#endif
...
int n;
TRACE("n=" << n);
// в этом случае немного неудобно, но жить можно
TRACE(("someFunc returned "<<someFunc(1,2,3)));
Re[5]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 08:31
Оценка:
Здравствуйте, Gleb Alexeev, Вы писали:

здесь более сложный пример того, что вы предлагали, но он не спасает от non-inline функций.
Re[4]: Препроцессор и переменное число аргументов
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.05 09:34
Оценка: 10 (3)
Здравствуйте, Gleb Alexeev, Вы писали:

С>>Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?


GA>Тут тоже макросами можно.


GA>
GA>#ifdef DEBUG
GA>#define TRACE(x) get_trace_stream()<<x
GA>#else
GA>define TRACE(x)
GA>#endif
GA>...
GA>int n;
GA>TRACE("n=" << n);
GA>// в этом случае немного неудобно, но жить можно
GA>TRACE(("someFunc returned "<<someFunc(1,2,3))); 
GA>


А можно и по другому макросами (ноги растут отсюда):
#ifdef DEBUG
#define TRACE() (false) ? std::cout : get_trace_stream()
#else
#define TRACE() (true) ? std::cout : std::cout
...
int n;
TRACE() << "n=" << n;

Последняя строка будет развернута либо в:
// Есть отладочная печать.
(false) ? std::cout : get_trace_stream() << "n=" << n;

либо в
(true) ? std::cout : std::cout << "n=" << n;

Соответственно, если DEBUG не определен, то хвост оператора ()?: вычислятся не будет.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 09:59
Оценка:
Здравствуйте, eao197, Вы писали:

Отличная идея , только я бы std::cout на какой-нибудь null_stream заменил бы (в случае, когда трассировка отключена).
Re[6]: Препроцессор и переменное число аргументов
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.05 10:03
Оценка:
Здравствуйте, Gleb Alexeev, Вы писали:

GA>Отличная идея , только я бы std::cout на какой-нибудь null_stream заменил бы (в случае, когда трассировка отключена).


Нет смысла. Ведь никуда ничего не выводится. Эта запись в случае !DEBUG будет эквивалентна:
std::cout;


А std::cout нужен для того, чтобы тип выражения в обоих ветках ?: был одинаковый -- std::ostream & (к примеру, или конкретный тип, к которому принадлежит std::cout).
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 10:06
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Gleb Alexeev, Вы писали:


GA>>Отличная идея , только я бы std::cout на какой-нибудь null_stream заменил бы (в случае, когда трассировка отключена).


E>Нет смысла. Ведь никуда ничего не выводится. Эта запись в случае !DEBUG будет эквивалентна:

E>
E>std::cout;
E>


E>А std::cout нужен для того, чтобы тип выражения в обоих ветках ?: был одинаковый -- std::ostream & (к примеру, или конкретный тип, к которому принадлежит std::cout).


Я через секунду это и сам понял, только удалить не успел . Поставьте мне минус, кто-нибудь, и сорри за шум.
Re[8]: Препроцессор и переменное число аргументов
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 22.08.05 10:10
Оценка: :)
Здравствуйте, Gleb Alexeev, Вы писали:

GA>>>Отличная идея , только я бы std::cout на какой-нибудь null_stream заменил бы (в случае, когда трассировка отключена).


E>>Нет смысла. Ведь никуда ничего не выводится. Эта запись в случае !DEBUG будет эквивалентна:

E>>
E>>std::cout;
E>>


E>>А std::cout нужен для того, чтобы тип выражения в обоих ветках ?: был одинаковый -- std::ostream & (к примеру, или конкретный тип, к которому принадлежит std::cout).


GA>Я через секунду это и сам понял, только удалить не успел . Поставьте мне минус, кто-нибудь, и сорри за шум.


Зачем же удалять?
Если что-то может быть истолковано не правильно, оно и будет истолковано неправильно ((С) кажется из законов Мерфи). Может еще у кого-то такой же вопрос возникнет, а тут сразу ответ готов.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Препроцессор и переменное число аргументов
От: Centaur Россия  
Дата: 22.08.05 14:20
Оценка:
Здравствуйте, Gleb Alexeev, Вы писали:

GA>Здравствуйте, Centaur, Вы писали:


C>>Дальше, оптимизирующий компилятор все обращения к log_print в нелогирующей версии выоптимизирует до нуля.

GA>Не факт.
GA>Боюсь, оптимизатор может не справиться с таким случаем (для этого компилятору пришлось бы доказать, что ни одна из non_inline_functionX не имеет побочных эффектов; может быть, что глобальная оптимизация с этим и справится, но гарантии нет):
GA>
GA>null_stream() << non_inline_function1() + non_inline_function2()/non_inline_function3();

Мы всё ещё говорим о логировании, или уже перешли к минимизирующим поверхность при заданном объёме представителям семейства непарнокопытных в условиях отсутствия атмосферного давления? Какие неинлайновые функции, какие побочные эффекты? Да тут use case примерно следующей сложности:
logstream << "Hello world, we are flying at " << altitude << "m, "
  "the temperatures of engines are " << writeContainer(engineTemp, ", ") << "\n";
Никаких неинлайновых функций, большей частью строковые литералы и локальные переменные, изредка конструкторы временных объектов, реализующих ленивую запись в поток. То есть, если нас попросят записаться в std::ostream, то мы запишемся в std::ostream, а если нас (сделают вид, что) запишут в null_stream без нашего участия, то мы и не будем ничего делать.
template <typename InIter>
class WriteRange
{
private:
  InIter begin_, end_;
  const char* separator_;
public:
  explicit WriteRange(InIter begin, InIter end, const char* separator)
  : begin_(begin), end_(end), separator_(separator)
  {}

  friend std::ostream& operator<<(std::ostream& stream, const WriteRange& wr)
  {
    InIter i = wr.begin_;
    stream << *i;
    for (++i; i != wr.end_; ++i)
    {
      stream << separator << *i;
    }
    return stream;
  }
};

template <typename Container>
WriteRange<typename Container::const_iterator>
writeContainer(const Container& container, const char* separator)
{
  return WriteRange<typename Container::const_iterator>(container.begin(), container.end(), separator);
}
Re[6]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 14:32
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Мы всё ещё говорим о логировании, или уже перешли к минимизирующим поверхность при заданном объёме представителям семейства непарнокопытных в условиях отсутствия атмосферного давления? Какие неинлайновые функции, какие побочные эффекты? Да тут use case примерно следующей сложности:

C>
C>logstream << "Hello world, we are flying at " << altitude << "m, "
C>  "the temperatures of engines are " << writeContainer(engineTemp, ", ") << "\n";
C>
Никаких неинлайновых функций, большей частью строковые литералы и локальные переменные, изредка конструкторы временных объектов, реализующих ленивую запись в поток. То есть, если нас попросят записаться в std::ostream, то мы запишемся в std::ostream, а если нас (сделают вид, что) запишут в null_stream без нашего участия, то мы и не будем ничего делать.




std::string lastErrorMsg() {
  // GetLastError(), FormatMessage и т.д. 
}
...
void foo() {
  trace_stream << lastErrorMsg();
}


Сферический конь, говоришь?
Соптимизирует, говоришь?

При желании можно придумать и более правдоподобный случай, когда тяжеловесный код будет выполняться впустую при отключенной трассировке.
Re[7]: Препроцессор и переменное число аргументов
От: Centaur Россия  
Дата: 22.08.05 15:11
Оценка:
Здравствуйте, Gleb Alexeev, Вы писали:

GA>
GA>std::string lastErrorMsg() {
GA>  // GetLastError(), FormatMessage и т.д. 
GA>}
GA>...
GA>void foo() {
GA>  trace_stream << lastErrorMsg();
GA>}
GA>


GA>Сферический конь, говоришь?

GA>Соптимизирует, говоришь?

Ну, во-первых, GetLastError у меня обычно вызывается сразу после возникновения ошибки, в конструкторе Win32Exception. Независимо от того, ведём мы логи или не ведём. А FormatMessage — соответственно в Win32Exception::what().

А во-вторых, даже в этом примере я попытаюсь максимально «ленивизировать» операцию — сделав lastErrorMsg классом и унеся всё тяжеловесное в его friend std::ostream& operator<<(std::ostream&, const lastErrorMsg&). В конструкторе останется один GetLastError(), и то только потому, что есть (минимальный) риск этот самый LastError прощёлкать клювом, успешно выполнив Win32API-операцию.

GA>При желании можно придумать и более правдоподобный случай, когда тяжеловесный код будет выполняться впустую при отключенной трассировке.


Пока не убеждён
Re[8]: Препроцессор и переменное число аргументов
От: Gleb Alexeev  
Дата: 22.08.05 15:32
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Ну, во-первых, GetLastError у меня обычно вызывается сразу после возникновения ошибки, в конструкторе Win32Exception. Независимо от того, ведём мы логи или не ведём. А FormatMessage — соответственно в Win32Exception::what().


C>А во-вторых, даже в этом примере я попытаюсь максимально «ленивизировать» операцию — сделав lastErrorMsg классом и унеся всё тяжеловесное в его friend std::ostream& operator<<(std::ostream&, const lastErrorMsg&). В конструкторе останется один GetLastError(), и то только потому, что есть (минимальный) риск этот самый LastError прощёлкать клювом, успешно выполнив Win32API-операцию.


С чего начали:
Замена log_stream на null_stream заставит оптимизатор полностью выкинуть код трассировки из приложения.

Чем закончили:
Я, нижеподписавшийся Centaur, лично никогда не вызываю не-inline функций при трассировке .

Удобство макросов типа ASSERT и TRACE в том, что их пишешь не задумываясь о стоимости, зная, что в релиз ничего из отладочного кода не попадет. Вы же призываете пользователя log_stream к дисциплине, ограничивая его удобство без особой на то причины (ниже ув. тов. eao197 дал более элегантное решение), тем более, что не-inline функция может не вызываться явно в выражении записи в поток.

C>Пока не убеждён

Ладно, другой пример:

namespace ThirdParty {
  class Something {
  public:
    std::string dump()const; //non-inline!
  };
}
...
void f(const ThirdParty::Something& smth) {
  log_stream << smth.dump();
  ...
}

Можно и еще более правдоподобно .
Re[3]: Препроцессор и переменное число аргументов
От: WinterMute Россия http://yarrr.ru
Дата: 22.08.05 16:22
Оценка:
WM>>
WM>>class LogOutput
WM>>{
WM>>   ...
WM>>   operator bool () const { return true; }
WM>>};
WM>>LogOutput log_print;

WM>>log_print << "text: " << 5;
WM>>


С>Нет, это немного не то. Автор топика хочет, чтобы в дебажной версии были логи, а в релизной нет. Т.е. один дефайн/ундеф — и нету никакого логирования. Или тут тоже как-то можно?

С>И под C не покатит, так что может оно и лучше, но не так универсально.

Можно, например, так :

class LogOutput
{
   ...
   operator bool () const { return true; }
};
LogOutput log_print;

ATLASSERT( log_print << "text: " << 5 );
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.