Самый простой и простой способ - просто переместить чек за пределы форматирования:
MyLogger log; // Probably a global variable or similar.
if (log.notice())
log << "notified!\n" << some_function("which takes forever to compute"
" and which it is impossible to elide if the check is inside log's"
" op<< or similar");
if (log.warn()) {
log << "warned!\n";
T x;
longer_code_computing(value_for, x); // easily separate out this logic
log << x;
}
Если вы действительно хотите сократить общий случай, вы можете использовать макрос:
#define LOG_NOTICE(logger) if (logger.notice()) logger <<
LOG_NOTICE(log) << "foo\n";
// instead of:
if (log.notice()) log << "foo\n";
Но экономия незначительна.
Один из возможных вариантов MyLogger:
struct MyLogger {
int priority_threshold;
bool notice() const { return notice_priority < current_priority; }
bool warn() const { return warn_priority < current_priority; }
bool etc() const { return etc_priority < current_priority; }
template<class T>
MyLogger& operator<<(T const &x) {
do_something_with(x);
return *this;
}
};
Проблема здесь заключается в том, что смешивается перегрузка операторов в стиле iostream с функцией журналирования в стиле printf, в частностиперевод манипуляторов и форматирование флагов / полей из iostreams в строку формата.Вы можете написать в поток строк, а затем разделить это на части в своей функции системного журнала или попробовать что-нибудь более необычное.Вышеупомянутый MyLogger работает проще всего, если он также содержит ссылку ostream, на которую он может пересылать, но вам понадобится еще несколько оп << перегруженных версий для iomanips (например, endl), если вы сделаете это. </p>