Более красивый метод:
#ifdef _DEBUG
#define DBOUT cout // or any other ostream
#else
#define DBOUT 0 && cout
#endif
DBOUT << "This is a debug build." << endl;
DBOUT << "Some result: " << doSomething() << endl;
Пока вы не делаете ничего странного, функции, вызываемые и передаваемые в DBOUT
, не будут вызываться в сборках релиза. Этот макрос работает из-за приоритета оператора и логического И; поскольку &&
имеет более низкий приоритет, чем <<
, выпуск сборки компилируется DBOUT << "a"
как 0 && (cout << "a")
. Логическое И не оценивает выражение справа, если выражение слева оценивается как ноль или false
; поскольку левое выражение всегда оценивается в ноль, правое выражение всегда удаляется любым компилятором, который стоит использовать, за исключением случаев, когда вся оптимизация отключена (и даже в этом случае явно недоступный код может игнорироваться).
Вот пример странных вещей, которые сломают этот макрос:
DBOUT << "This is a debug build." << endl, doSomething();
Смотрите запятые. doSomething()
будет вызываться всегда, независимо от того, определен ли _DEBUG
. Это потому, что оператор оценивается в сборках релиза как:
(0 && (cout << "This is a debug build." << endl)), doSomething();
// evaluates further to:
false, doSomething();
Чтобы использовать запятые с этим макросом, запятую необходимо заключить в скобки, например:
DBOUT << "Value of b: " << (a, b) << endl;
Другой пример:
(DBOUT << "Hello, ") << "World" << endl; // Compiler error on release build
В сборках выпуска это оценивается как:
(0 && (cout << "Hello, ")) << "World" << endl;
// evaluates further to:
false << "World" << endl;
, что приводит к ошибке компилятора, поскольку bool
не может быть смещен влево указателем char
, если не определен пользовательский оператор. Этот синтаксис также вызывает дополнительные проблемы:
(DBOUT << "Result: ") << doSomething() << endl;
// evaluates to:
false << doSomething() << endl;
Точно так же, как когда запятая использовалась плохо, doSomething()
все еще вызывается, потому что ее результат должен быть передан оператору левого сдвига. (Это может произойти, только если определен пользовательский оператор, который смещает влево bool
на указатель char
; в противном случае возникает ошибка компилятора.)
Не ставьте скобки DBOUT << ...
. Если вы хотите заключить в скобки буквенное целочисленное смещение, то заключите его в скобки, но я не знаю ни одной веской причины заключить в скобки оператор потока.