Simplify the Q_FOREACH macro when using C++17

This way there is only one for loop, which is more optimizer friendly

Change-Id: Iaa02026627d5259c3eea1ff5664e8f22664eef73
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2018-10-29 12:21:38 +01:00 committed by Olivier Goffart (Woboq GmbH)
parent 22788194f9
commit 0330b967f2
3 changed files with 51 additions and 1 deletions

View File

@ -1005,6 +1005,15 @@ QForeachContainer<typename std::decay<T>::type> qMakeForeachContainer(T &&t)
}
}
#if __cplusplus >= 201703L
// Use C++17 if statement with initializer. User's code ends up in a else so
// scoping of different ifs is not broken
#define Q_FOREACH(variable, container) \
for (auto _container_ = QtPrivate::qMakeForeachContainer(container); \
_container_.i != _container_.e; ++_container_.i) \
if (variable = *_container_.i; false) {} else
#else
// Explanation of the control word:
// - it's initialized to 1
// - that means both the inner and outer loops start
@ -1019,7 +1028,7 @@ for (auto _container_ = QtPrivate::qMakeForeachContainer(container); \
_container_.control && _container_.i != _container_.e; \
++_container_.i, _container_.control ^= 1) \
for (variable = *_container_.i; _container_.control; _container_.control = 0)
#endif
#endif // QT_NO_FOREACH
#define Q_FOREVER for(;;)

View File

@ -2,3 +2,4 @@ CONFIG += testcase
TARGET = tst_qglobal
QT = core testlib
SOURCES = tst_qglobal.cpp qglobal.c
contains(QT_CONFIG, c++1z): CONFIG += c++1z

View File

@ -126,6 +126,46 @@ void tst_QGlobal::for_each()
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.count());
// Should also work with an existing variable
int local;
counter = 0;
foreach (local, list) {
QCOMPARE(local, counter++);
}
QCOMPARE(counter, list.count());
QCOMPARE(local, counter - 1);
// Test the macro does not mess if/else conditions
counter = 0;
if (true)
foreach (int i, list)
QCOMPARE(i, counter++);
else
QFAIL("If/Else mismatch");
QCOMPARE(counter, list.count());
counter = 0;
if (false)
foreach (int i, list)
if (i) QFAIL("If/Else mismatch");
else QFAIL("If/Else mismatch");
else
foreach (int i, list)
if (false) { }
else QCOMPARE(i, counter++);
QCOMPARE(counter, list.count());
// break and continue
counter = 0;
foreach (int i, list) {
if (i == 0)
continue;
QCOMPARE(i, (counter++) + 1);
if (i == 3)
break;
}
QCOMPARE(counter, 3);
}
void tst_QGlobal::qassert()