2016-12-31 10 views
1

Я пытаюсь использовать конструкторы классов и деконструкторы для представления и форматирования области в моих файлах журналов с помощью идиомы RAII. Используя один #define, он печатает «{» и увеличивает глобальный уровень отступов, чтобы следующая строка журнала была напечатана на этом уровне отступов.Предотвращение деконструкции анонимной переменной, определенной в макросе до конца области

LogScopeRAII Предполагается напечатать "}" и естественно уменьшить глобальный уровень отступа, поскольку он выходит за пределы области действия в конце Foo(). Однако поведение, которое я вижу, заключается в том, что LogScopeRAII деконструируется сразу после его построения.

Гипотезы: Я думаю, что проблема в том, что LogScopeRAII создается на РИТ задания (и, таким образом, анонимно?) И уничтожается в конце строки, но я не уверен, что делать около. Я подумал, что LOG_ANONYMOUS_VARIABLE в VSCOPE_F сделал бы трюк и заставил его остаться, но это не так.

Вопрос: Как я могу остановить LogScopeRAII от деконструирования до тех пор, пока вызывающая функция не выйдет из области видимости?

/* Header */ 
LogScopeRAII::LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, const char* format, ...) 
{ 
    // ... 
    // print "{" and then increase an indentation global var 
} 

LogScopeRAII::~LogScopeRAII() 
{ 
    // ... 
    // print "}" and then decrease the indentation global var 
} 

#define LOG_ANOMYMOUS_VARIABLE(str) LOG_CONCAT(str, __LINE__) 

#define VSCOPE_F(verbosity, ...) \ 
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) = \ 
((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__} 

#define SCOPE_F(verbosity_name, ...) VSCOPE_F(Verbosity_ ## verbosity_name, __VA_ARGS__) 

#define SCOPE_FUNCTION(INFO) SCOPE_F(verbosity_name, __FUNCTION__) 

/* Implementation */ 
void Foo() 
{ 
    SCOPE_FUNCTION(INFO) // print "{" and increase indentation 
    for (size_t i = 0; i < 3; ++i) 
    { 
     // do work 
     LOG(INFO, "Work logged"); 
    } 
    // print "}" and decrease indentation 
} 

Желаемый результат:

{ Foo() 
    "Work Logged" // Note indentation 
} 0.23 s: Foo() 

EDIT: ВАРЕНЬЕ ПРОБЛЕМУ ВНИЗ

Суть его заключается в следующем: не похоже, работает тройная.

Это работает:

LogScopeRAII a(LogScopeRAII{ Verbosity_INFO, __FILE__, static_cast<unsigned>(__LINE__), "" }); 

Но это не делает:

LogScopeRAII a(((Verbosity_INFO) > indent) ? LogScopeRAII() : LogScopeRAII{ Verbosity_INFO, __FILE__, static_cast<unsigned>(__LINE__), "" }); 

я получаю:

{ 
} 
Work logged 
Work logged 
Work logged 
} 
constructCounter: 1 
destructCounter: 2 
Exiting... 
+1

фарш это в макросе на данный момент немного преждевременно. Перерыв в реальном коде и заставить его работать так, как вы хотите, а затем макросы объявлений по своему желанию. –

+0

См. Редактирование. Принял ваше предложение. Кажется, что троянец не работает? – Stradigos

+1

Возможно, конструкция перемещения LogScopeRAII нарушена. «Рабочая версия» скроет проблему из-за копирования, но нет копии с условной версией оператора. По крайней мере, в деструкторе должен быть код, чтобы не испускать '}', если это временное, которое было перемещено из и т. Д. –

ответ

1
#define VSCOPE_F(verbosity, ...) \ 
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) = \ 
((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__} 

должен быть

#define VSCOPE_F(verbosity, ...) \ 
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) \ 
(((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__}) 

иначе вы используете экземпляр-копию временной переменной.

(Вы также можете исправить вы двигаетесь-конструктор и деструктор, чтобы ваш текущий MACRO)

+0

Это, похоже, не имеет значения. Однако, если я удалю тройную операцию и просто перейду с LogScopeRAII с параметрами, которые она работает. Что может быть неправильно с тройной? Я подтвердил, что он оценивает тот же LogScopeRAII - тот, у кого есть параметры - в любом случае, так что это что-то еще. Он продолжает строить и деконструировать сразу, а затем деконструировать еще один раз в конце ... что странно, потому что с ним нет подходящего конструктора. Не знаю, как это возможно. Вот пастебин моей тестовой установки: http://pastebin.com/8mSjVnPN – Stradigos

+0

В конечном счете, это проблема с MSVC C++ 14, потому что она отлично работает в GCC. Я предполагаю, что это не вызывает копию в GCC, но делает это в MSVC. См. Http://stackoverflow.com/questions/22078029/why-does-the-ternary-operator-prevent-return-value-optimization и http://stackoverflow.com/questions/11914691/copy-elision-move- constructor-not-called-when-use-trernary-expression-in-retur Я добавил static_cast , где это необходимо, чтобы исправить его. Любопытно, есть ли лучший способ, но проблема все же решена. Спасибо за помощь. – Stradigos