diff options
Diffstat (limited to 'src/corelib/thread/qthread.h')
-rw-r--r-- | src/corelib/thread/qthread.h | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 45786537e2..03b5424bb6 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -42,6 +43,20 @@ #include <QtCore/qobject.h> +// For QThread::create. The configure-time test just checks for the availability +// of std::future and std::async; for the C++17 codepath we perform some extra +// checks here (for std::invoke and C++14 lambdas). +#if QT_CONFIG(cxx11_future) +# include <future> // for std::async +# include <functional> // for std::invoke; no guard needed as it's a C++98 header + +# if defined(__cpp_lib_invoke) && __cpp_lib_invoke >= 201411 \ + && defined(__cpp_init_captures) && __cpp_init_captures >= 201304 \ + && defined(__cpp_generic_lambdas) && __cpp_generic_lambdas >= 201304 +# define QTHREAD_HAS_VARIADIC_CREATE +# endif +#endif + #include <limits.h> QT_BEGIN_NAMESPACE @@ -98,6 +113,23 @@ public: bool event(QEvent *event) Q_DECL_OVERRIDE; int loopLevel() const; +#ifdef Q_QDOC + template <typename Function, typename... Args> + static QThread *create(Function &&f, Args &&... args); + template <typename Function> + static QThread *create(Function &&f); +#else +# if QT_CONFIG(cxx11_future) +# ifdef QTHREAD_HAS_VARIADIC_CREATE + template <typename Function, typename... Args> + static QThread *create(Function &&f, Args &&... args); +# else + template <typename Function> + static QThread *create(Function &&f); +# endif // QTHREAD_HAS_VARIADIC_CREATE +# endif // QT_CONFIG(cxx11_future) +#endif // Q_QDOC + public Q_SLOTS: void start(Priority = InheritPriority); void terminate(); @@ -127,10 +159,86 @@ protected: private: Q_DECLARE_PRIVATE(QThread) +#if QT_CONFIG(cxx11_future) + static QThread *createThreadImpl(std::future<void> &&future); +#endif + friend class QCoreApplication; friend class QThreadData; }; +#if QT_CONFIG(cxx11_future) + +#if defined(QTHREAD_HAS_VARIADIC_CREATE) +// C++17: std::thread's constructor complying call +template <typename Function, typename... Args> +QThread *QThread::create(Function &&f, Args &&... args) +{ + using DecayedFunction = typename std::decay<Function>::type; + auto threadFunction = + [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void + { + (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...); + }; + + return createThreadImpl(std::async(std::launch::deferred, + std::move(threadFunction), + std::forward<Args>(args)...)); +} +#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304 +// C++14: implementation for just one callable +template <typename Function> +QThread *QThread::create(Function &&f) +{ + using DecayedFunction = typename std::decay<Function>::type; + auto threadFunction = + [f = static_cast<DecayedFunction>(std::forward<Function>(f))]() mutable -> void + { + (void)f(); + }; + + return createThreadImpl(std::async(std::launch::deferred, std::move(threadFunction))); +} +#else +// C++11: same as C++14, but with a workaround for not having generalized lambda captures +namespace QtPrivate { +template <typename Function> +struct Callable +{ + explicit Callable(Function &&f) + : m_function(std::forward<Function>(f)) + { + } + +#if defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS) + // Apply the same semantics of a lambda closure type w.r.t. the special + // member functions, if possible: delete the copy assignment operator, + // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure]) + ~Callable() = default; + Callable(const Callable &) = default; + Callable(Callable &&) = default; + Callable &operator=(const Callable &) = delete; + Callable &operator=(Callable &&) = default; +#endif + + void operator()() + { + (void)m_function(); + } + + typename std::decay<Function>::type m_function; +}; +} // namespace QtPrivate + +template <typename Function> +QThread *QThread::create(Function &&f) +{ + return createThreadImpl(std::async(std::launch::deferred, QtPrivate::Callable<Function>(std::forward<Function>(f)))); +} +#endif // QTHREAD_HAS_VARIADIC_CREATE + +#endif // QT_CONFIG(cxx11_future) + #else // QT_NO_THREAD class Q_CORE_EXPORT QThread : public QObject |