2012-02-16 2 views
3

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

DBG(5) << "Foobar" << std::endl; 

5 означает уровень сообщения, если уровень отладки меньше чем 5, оно не будет печатать сообщение. В настоящее время она реализуется как:

#define DBG(level) !::Logger::IsToDebug((level)) ? : ::Logger::Debug 

В основном IsToDebug проверки, если сообщение должно быть напечатано, и возвращает истину, когда он должен. Logger::Debug - это std :: ostream. Это также работает с gcc и clang, однако clang генерирует результат выражения без использования предупреждений. Согласно this email, это тоже не нравится.

Префикс с (void) не работает, он будет отличать вещь до ?, что приведет к ошибке компиляции (void не может быть преобразован в bool, очевидно). Другая проблема с этим синтаксисом заключается в том, что он использует gcc extension.

делать вещи, как #define DBG(x) if (::Logger::IsToDebug((x))) ::Logger::Debug решает эту проблему, но это верный способ разрушить вашу программу (if (foo) DBG(1) << "foo"; else ...) (и я не могу поставить все это в do { ... } while(0) из-за того, как называется макро.)

только более или менее жизнеспособным решением я придумал это (при условии, IsToDebug возвращает 0 или 1):

#define DBG(level) for(int dbgtmpvar = ::Logger::IsToDebug((level)); \ 
         dbgtmpvar > 0; --dbgtmpvar) ::Logger::Debug 

что выглядит как массовое убийство (не считая, что это во время выполнения накладных)

+0

Верно ли ваше использование тернарного оператора? Где второе выражение? – Nawaz

+1

Представляется, что это непреднамеренное использование тройного расширения gcc. DirtY iCE, вероятно, думал, что ничего там не поместит, но на самом деле он ставит там bool. – Joe

+0

Как я уже упоминал, это расширение gcc (это также означает, что clang также поддерживается), см. Http://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals –

ответ

4

Я думаю, вы должны использовать трехмерный оператор, поскольку он определен в стандарте, а не в расширении компилятора. Чтобы использовать стандартный тернарный оператор, вы также должны предоставить второе выражение. Для этого вы можете определить класс потока, полученный из std::ostream, который ничего не печатает в любом месте. Объект такого класса может использоваться как второе выражение.

class oemptystream : std::ostream 
{ 
    //.. 
}; 

extern oemptystream nout; //declaration here, as definition should go to .cpp 

затем

#define DBG(level) ::Logger::IsToDebug((level))? nout : ::Logger::Debug 

Теперь, если вы используете этот макрос, то во время выполнения, выражение сводилось бы ни это:

nout << "message"; 

Или это,

::Logger::Debug << "message"; 

В любом случае, это в значительной степени нравится e это:

std::cout << "message"; 

Так что я надеюсь, что это не должно давать предупреждения компилятора.

+0

на самом деле, он сводится к 'nout' или' :: Logger :: Debug << "message"; 'Он уменьшится до двух вы упомянули, если бы вы поставили круглые скобки вокруг выражения в макросе. Сказав, что, например, использование 'std :: cout' вместо' nout' будет работать, так как 'std :: cout;' само по себе ничего не делает. Использование просто 'false' вместо' nout' тоже похоже на работу, хотя я не уверен, что он стандартный. И даже это не дает предупреждения. –

+1

Обратите внимание, что вам не нужно выводить из 'std :: ostream': просто используйте' std :: ostream', который находится в состоянии сбоя, например. 'std :: ostream nout (0)'. Лично я не большой поклонник этого, потому что он все еще оценивает выражения, переданные операторам вывода. То, что вы, вероятно, хотите, - это что-то вроде '! :: Logger :: IsToDebug ((level)) || :: Logger :: Debug'. Это должно иметь правильный приоритет и предотвращать оценку выражений. –

+0

Думаю, я поеду с ':: Logger :: IsToDebug ((level)) && :: Logger :: Debug'. Использует '!' И '||' лучше, чем '&&'? –

 Смежные вопросы

  • Нет связанных вопросов^_^