Давайте предположим, что у нас есть несколько уровней ведения журнала: трассировка, отладка, информация, ошибка.
Мне было интересно, если есть способ написать следующий код:
enum log_level = {trace, debug, info, error};
log_level global_log_level = info;
void log(log_level level, string& message){
if (level >= global_log_level){
std::cout << message << std::endl;
}
}
string create_message(){
...
}
log_level level = debug;
log (level, create_message());
без вызова create_message, если уровень меньше, чем global_severity_level. Действительно, create_message может быть довольно длинным, и независимо от того, что он создает строку. Если есть много «отладочных» журналов, они могут стать существенными издержками при работе в режиме без отладки.
Я знаю, что это можно сделать, если функция «log» является макросом, вызывающим create_message (), только если severity> minimal_severity; но разве нет другого способа сделать это без макросов?
РЕДАКТИРОВАТЬ
Выше я не указал create_message, потому что это может быть что угодно, в частности:
log(level, "Created object " + my_object.getName());
В этом случае, есть ли способ записи журнала таким образом, чтобы полная строка не создавалась относительно прозрачным способом для программиста, вызывающего журнал?
Большое спасибо
Похоже на @sftrabbit, но, как подсказывает @ipc.
Используйте шаблон, чтобы избежать механизма std :: function, и компилятор может встроить это, и, таким образом, он, надеемся, будет быстрее.
template< typename F >
void log(log_level level, F message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
Есть несколько альтернатив. Интересно пройти create_message
как std::function<std::string()>
и позвони изнутри log
:
void log(log_level level, std::function<std::string()> message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
Тогда вы бы назвали это так:
log(level, create_message);
Это может работать с произвольными выражениями в качестве аргументов, если вы заключаете их в лямбду:
log(level, [&](){ return "Created object " + my_object.getName(); });
Если вы действительно не хотите, чтобы аргумент оценивался вообще (как вы описали в комментариях), то вам нужно проверить уровень за пределами вызова:
if (level >= global_log_level) {
log(level, create_message());
}
Ответ @sftrabbit является предпочтительным. Но просто если вы не хотите изменять log (), вы можете вызвать его:
log (level, (level >= global_log_level)? create_message() : "");
Вы можете создать макрос
#define log(level, message) { \
if(level >= global_log_level) {\
cout << message; }}
Теперь, если вы позвоните
log(debug, create_message());
create_message будет вызываться, только если желаемый уровень отладки.