summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2016-11-09 17:37:52 +0100
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2016-12-10 18:11:38 +0000
commite5e26294f237d972122dd9d757956a8d7eea0294 (patch)
treee5e89f6dcb748b8909c5b2bd8f5369b898f9c6d7
parent4aebbef8ab94723d59679f30005b114197c995b9 (diff)
foreach: do not use operators that trigger non-evaluated contexts
Namely: decltype(). Ideally we'd want C++17's template constructor argument deduction, but instead use the C++11 solution: a factory function. This enables using things such as lambdas in the container argument. Change-Id: Idba64d8069d15bbafe54cfdebe24b1fba1eb8d0a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/global/qglobal.h21
-rw-r--r--tests/auto/corelib/global/qglobal/tst_qglobal.cpp7
2 files changed, 27 insertions, 1 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 99be82f8c3..f64ab143ef 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -44,6 +44,8 @@
#ifdef __cplusplus
# include <type_traits>
# include <cstddef>
+# include <type_traits>
+# include <utility>
#endif
#include <stddef.h>
@@ -943,17 +945,34 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
#ifndef QT_NO_FOREACH
+namespace QtPrivate {
+
template <typename T>
class QForeachContainer {
QForeachContainer &operator=(const QForeachContainer &) Q_DECL_EQ_DELETE;
public:
QForeachContainer(const T &t) : c(t) {}
QForeachContainer(T &&t) : c(std::move(t)) {}
+ QForeachContainer(const QForeachContainer &other)
+ : c(other.c),
+ i(c.begin()),
+ e(c.end()),
+ control(other.control)
+ {
+ }
+
const T c;
typename T::const_iterator i = c.begin(), e = c.end();
int control = 1;
};
+template<typename T>
+QForeachContainer<typename std::decay<T>::type> qMakeForeachContainer(T &&t)
+{
+ return QForeachContainer<typename std::decay<T>::type>(std::forward<T>(t));
+}
+
+}
// Explanation of the control word:
// - it's initialized to 1
// - that means both the inner and outer loops start
@@ -964,7 +983,7 @@ public:
// - if there was a break inside the inner loop, it will exit with control still
// set to 1; in that case, the outer loop will invert it to 0 and will exit too
#define Q_FOREACH(variable, container) \
-for (QForeachContainer<typename std::remove_reference<decltype(container)>::type> _container_((container)); \
+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)
diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
index bb6ec1c8e7..083526fdc4 100644
--- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
+++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
@@ -102,6 +102,13 @@ void tst_QGlobal::for_each()
QCOMPARE(i, counter++);
}
QCOMPARE(counter, list.count());
+
+ // check whether we can use a lambda
+ counter = 0;
+ foreach (int i, [&](){ return list; }()) {
+ QCOMPARE(i, counter++);
+ }
+ QCOMPARE(counter, list.count());
}
void tst_QGlobal::qassert()