QThread::create: move implementation out of line

Now that we accept STL datatypes in our ABI, expose a factory
function that takes a std::future<void>, and hide the QThread
subclass in our implementation. This also solves the problem
of a non-exported polymorphic class that would generate duplicate
vtables / typeinfo in all TUs.

Change-Id: I70a5c301e7c589de1a4a189db39b86b956d1ba0d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2017-09-15 17:53:48 +01:00
parent e5033a5c9b
commit 0d0ad598c5
2 changed files with 85 additions and 78 deletions

View File

@ -925,6 +925,30 @@ bool QThread::isInterruptionRequested() const
\sa start()
*/
#ifdef QTHREAD_HAS_CREATE
class QThreadCreateThread : public QThread
{
public:
explicit QThreadCreateThread(std::future<void> &&future)
: m_future(std::move(future))
{
}
private:
void run() override
{
m_future.get();
}
std::future<void> m_future;
};
QThread *QThread::createThreadImpl(std::future<void> &&future)
{
return new QThreadCreateThread(std::move(future));
}
#endif // QTHREAD_HAS_CREATE
/*!
\class QDaemonThread
\since 5.5

View File

@ -165,98 +165,81 @@ protected:
private:
Q_DECLARE_PRIVATE(QThread)
#ifdef QTHREAD_HAS_CREATE
static QThread *createThreadImpl(std::future<void> &&future);
#endif
friend class QCoreApplication;
friend class QThreadData;
};
#ifdef QTHREAD_HAS_CREATE
namespace QtPrivate {
class QThreadCreateThread : public QThread
{
public:
#if defined(QTHREAD_HAS_VARIADIC_CREATE)
// C++17: std::thread's constructor complying call
template <typename Function, typename... Args>
explicit QThreadCreateThread(Function &&f, Args &&... args)
: m_future(std::async(std::launch::deferred,
[f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))](auto &&... largs) mutable -> void
{
(void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
}, std::forward<Args>(args)...))
{
}
#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
// C++14: implementation for just one callable
template <typename Function>
explicit QThreadCreateThread(Function &&f)
: m_future(std::async(std::launch::deferred,
[f = static_cast<typename std::decay<Function>::type>(std::forward<Function>(f))]() mutable -> void
{
(void)f();
}))
{
}
#else
private:
// C++11: same as C++14, but with a workaround for not having generalized lambda captures
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;
};
public:
template <typename Function>
explicit QThreadCreateThread(Function &&f)
: m_future(std::async(std::launch::deferred, Callable<Function>(std::forward<Function>(f))))
{
}
#endif // QTHREAD_HAS_VARIADIC_CREATE
private:
void run() override
{
m_future.get();
}
std::future<void> m_future;
};
} // namespace QtPrivate
#ifdef QTHREAD_HAS_VARIADIC_CREATE
// C++17: std::thread's constructor complying call
template <typename Function, typename... Args>
QThread *QThread::create(Function &&f, Args &&... args)
{
return new QtPrivate::QThreadCreateThread(std::forward<Function>(f), std::forward<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)...));
}
#else
#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
// C++14: implementation for just one callable
template <typename Function>
QThread *QThread::create(Function &&f)
{
return new QtPrivate::QThreadCreateThread(std::forward<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