diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2016-10-17 13:00:04 +0200 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2016-10-18 16:06:28 +0000 |
commit | e80faf3db61ca9c701cd86876e3bce8e33226576 (patch) | |
tree | 279ad81c075f711ea776f5cff37db88c9571d129 /src/corelib | |
parent | 3a1245fdace1b008018dfb6b6334d5ebaec81b5e (diff) |
QTimer: don't circumvent <chrono> safety net
By templating on the <chrono> types and unconditionally using
duration_cast to coerce the duration into a milliseconds, we
violate a principal design rule of <chrono>, namely that non-
narrowing conversions are implicit, but narrowing conversions
need duration_cast. By accepting any duration, we allow non-
sensical code such as
QTimer::singleShot(10us, ...)
to compile, which is misleading, since it's actually a zero-
timeout timer.
Overloading a non-template with a template also has adverse
effects: it breaks qOverload().
Fix by replacing the function templates with functions that
just take std::chrono::milliseconds. This way, benign code
such as
QTimer::singleShot(10s, ...)
QTimer::singleShot(10min, ...)
QTimer::singleShot(1h, ...)
work as expected, but attempts to use sub-millisecond
resolution fails to compile / needs an explicit user-
provided duration_cast.
To allow future extension to more precise timers, forcibly
inline the functions, so they don't partake in the ABI of the
class and we can later support sub-millisecond resolution by
simply taking micro- or nano- instead of milliseconds.
Change-Id: I12c9a98bdabefcd8ec18a9eb09f87ad908d889de
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qtimer.cpp | 12 | ||||
-rw-r--r-- | src/corelib/kernel/qtimer.h | 36 |
2 files changed, 24 insertions, 24 deletions
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 6d39233aa7..4a5738a6dc 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -533,7 +533,7 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv */ /*! - \fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member) + \fn void QTimer::singleShot(std::chrono::milliseconds msec, const QObject *receiver, const char *member) \since 5.8 \overload \reentrant @@ -545,13 +545,13 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv create a local QTimer object. The \a receiver is the receiving object and the \a member is the slot. The - time interval is given in the duration object \a value. + time interval is given in the duration object \a msec. \sa start() */ /*! - \fn void QTimer::singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member) + \fn void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, const QObject *receiver, const char *member) \since 5.8 \overload \reentrant @@ -563,18 +563,18 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv create a local QTimer object. The \a receiver is the receiving object and the \a member is the slot. The - time interval is given in the duration object \a value. The \a timerType affects the + time interval is given in the duration object \a msec. The \a timerType affects the accuracy of the timer. \sa start() */ /*! - \fn void QTimer::start(std::chrono::duration<Rep, Period> value) + \fn void QTimer::start(std::chrono::milliseconds msec) \since 5.8 \overload - Starts or restarts the timer with a timeout of duration \a value. + Starts or restarts the timer with a timeout of duration \a msec milliseconds. If the timer is already running, it will be \l{QTimer::stop()}{stopped} and restarted. diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h index 1567fe760c..4f934d0367 100644 --- a/src/corelib/kernel/qtimer.h +++ b/src/corelib/kernel/qtimer.h @@ -165,38 +165,40 @@ Q_SIGNALS: public: #if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC) - template <class Rep, class Period> - void setInterval(std::chrono::duration<Rep, Period> value) + Q_ALWAYS_INLINE + void setInterval(std::chrono::milliseconds value) { - setInterval(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()); + setInterval(value.count()); } + Q_ALWAYS_INLINE std::chrono::milliseconds intervalAsDuration() const { return std::chrono::milliseconds(interval()); } + Q_ALWAYS_INLINE std::chrono::milliseconds remainingTimeAsDuration() const { return std::chrono::milliseconds(remainingTime()); } - template <class Rep, class Period> - static void singleShot(std::chrono::duration<Rep, Period> value, const QObject *receiver, const char *member) + Q_ALWAYS_INLINE + static void singleShot(std::chrono::milliseconds value, const QObject *receiver, const char *member) { - singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), receiver, member); + singleShot(int(value.count()), receiver, member); } - template <class Rep, class Period> - static void singleShot(std::chrono::duration<Rep, Period> value, Qt::TimerType timerType, const QObject *receiver, const char *member) + Q_ALWAYS_INLINE + static void singleShot(std::chrono::milliseconds value, Qt::TimerType timerType, const QObject *receiver, const char *member) { - singleShot(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count()), timerType, receiver, member); + singleShot(int(value.count()), timerType, receiver, member); } - template <class Rep, class Period> - void start(std::chrono::duration<Rep, Period> value) + Q_ALWAYS_INLINE + void start(std::chrono::milliseconds value) { - start(int(std::chrono::duration_cast<std::chrono::milliseconds>(value).count())); + start(int(value.count())); } #endif @@ -215,15 +217,13 @@ private: const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); #if QT_HAS_INCLUDE(<chrono>) - template <class Rep, class Period> - static Qt::TimerType defaultTypeFor(std::chrono::duration<Rep, Period> interval) - { return defaultTypeFor(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count())); } + static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) + { return defaultTypeFor(int(interval.count())); } - template <class Rep, class Period> - static void singleShotImpl(std::chrono::duration<Rep, Period> interval, Qt::TimerType timerType, + static void singleShotImpl(std::chrono::milliseconds interval, Qt::TimerType timerType, const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) { - singleShotImpl(int(std::chrono::duration_cast<std::chrono::milliseconds>(interval).count()), + singleShotImpl(int(interval.count()), timerType, receiver, slotObj); } #endif |