From e5e26294f237d972122dd9d757956a8d7eea0294 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 9 Nov 2016 17:37:52 +0100 Subject: 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 --- src/corelib/global/qglobal.h | 21 ++++++++++++++++++++- tests/auto/corelib/global/qglobal/tst_qglobal.cpp | 7 +++++++ 2 files changed, 27 insertions(+), 1 deletion(-) 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 # include +# include +# include #endif #include @@ -943,17 +945,34 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic #ifndef QT_NO_FOREACH +namespace QtPrivate { + template 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 +QForeachContainer::type> qMakeForeachContainer(T &&t) +{ + return QForeachContainer::type>(std::forward(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::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() -- cgit v1.2.3