Details
-
Bug
-
Resolution: Won't Do
-
P3: Somewhat important
-
None
-
5.15.2, 6.1.2
-
None
Description
Summary
qDebug() and qCDebug() look very similar, but they can't be used in the same way as an rvalue.
Description
First, let's talk about qDebug and friends (not the absence of "c" — logging without categories). They are simple macros exanding to a call to a constructor of QMessageLogger plus a relevant method's name — without parenthesis which are supposed to be added by user. If debugging is disabled through compile-time macro definitions, then qDebug "conveniently" expands to while (false) QMessageLogger().noDebug, and this is the point when we start having problems. It's not an rvalue anymore, however still can be chained on the right side.
Now, let's switch to categories and their macros. qCDebug expands to something even more horrific:
# define qCDebug(category, ...) \ for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \ QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, category().categoryName()).debug(__VA_ARGS__)
and there is a good reason for that, which naturally flows from a bad language design.
Changing it to the usual do {} while (false) boilerplate is not an option, because we'd lose an ability to chain right-hand-side streaming operations at all.
And if we use if statement, it will kinda works most of the time, until you write something like if (cond) qCDebug(lcMine) << "Yahaha!"; else doSomething(); — in which case a compiler will bring a curse down on you and all your family for not using disambiguating braces (which you should always use anyway). That's pretty evident and self-explanatory case of leaking abstractions / implementation details.
Next, I wanted to suggest inline variadic functions, but seems like GCC couldn't implement them for the last 20 years. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10980
Steps to reproduce
Compile this with and without
#define QT_NO_DEBUG_OUTPUT #include <QDebug> #include <QLoggingCategory> int main(int argc, char *argv[]) { (qDebug() << "Hello, world").nospace() << 42 << "."; }
Expected result
Should compile and run regardless of the presence of QT_NO_DEBUG_OUTPUT definition.
Actual result
Various compiler error messages about broken syntax and semantics.
Suggested solution
Use trenary operator to conditionally return real logger instance or a fake noDebug one. Compiler should be able to figure out the rest.
Besides, this while (false) in QT_NO_QDEBUG_MACRO definition looks like a micro-optimization which should be done by compiler too, since noDebug implementation just drops all its content into void.