Ленивая регистрация в переполнении стека

Давайте предположим, что у нас есть несколько уровней ведения журнала: трассировка, отладка, информация, ошибка.
Мне было интересно, если есть способ написать следующий код:

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());

В этом случае, есть ли способ записи журнала таким образом, чтобы полная строка не создавалась относительно прозрачным способом для программиста, вызывающего журнал?

Большое спасибо

8

Решение

Похоже на @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;
}
}
5

Другие решения

Есть несколько альтернатив. Интересно пройти 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());
}
6

Ответ @sftrabbit является предпочтительным. Но просто если вы не хотите изменять log (), вы можете вызвать его:

log (level, (level >= global_log_level)? create_message() : "");
1

Вы можете создать макрос



#define log(level, message) { \
if(level >= global_log_level) {\
cout << message; }}

Теперь, если вы позвоните

log(debug, create_message());

create_message будет вызываться, только если желаемый уровень отладки.

1
По вопросам рекламы [email protected]