diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp index dfa9b670e7..4fe3f7e99e 100644 --- a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp @@ -72,3 +72,30 @@ i.toBack(); while (i.hasPrevious()) qDebug() << i.previous(); //! [2] + +//! [3] +using NetworkReply = std::variant; + +enum class IOError { FailedToRead, FailedToWrite }; +using IOResult = std::variant; +//! [3] + +//! [4] +QFuture future = QtConcurrent::run([url] { + ... + return NetworkReply(QNetworkReply::TimeoutError); +}).then([](NetworkReply reply) { + if (auto error = std::get_if(&reply)) + return IOResult(IOError::FailedToRead); + + auto data = std::get_if(&reply); + // try to write *data and return IOError::FailedToWrite on failure + ... +}); + +auto result = future.result(); +if (auto filePath = std::get_if(&result)) { + // do something with *filePath +else + // process the error +//! [4] diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index 8b354fe114..fc2892ad2d 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -51,9 +51,31 @@ QFuture provides a \l{Java-style iterators}{Java-style iterator} (QFutureIterator) and an \l{STL-style iterators}{STL-style iterator} - (QFuture::const_iterator). Using these iterators is another way to access + (QFuture::const_iterator). Using these iterators is another way to access results in the future. + If the result of one asynchronous computation needs to be passed + to another, QFuture provides a convenient way of chaining multiple + sequential computations using then(). Additionally, onFailed() can be used + to handle any failures that occurred in the chain. Note that QFuture relies + on exceptions for the error handling. If using exceptions is not an option, + you can still indicate the error state of QFuture, by making the error type + part of the QFuture type. For example, you can use std::variant, std::any or + similar for keeping the result or failure or make your custom type. + + The example below demonstrates how the error handling can be done without + using exceptions. Let's say we want to send a network request to obtain a large + file from a network location. Then we want to write it to the file system and + return its location in case of a success. Both of these operations may fail + with different errors. So, we use std::variant to keep the result + or error: + + \snippet code/src_corelib_thread_qfuture.cpp 3 + + And we combine the two operations using then(): + + \snippet code/src_corelib_thread_qfuture.cpp 4 + QFuture also offers ways to interact with a runnning computation. For instance, the computation can be canceled with the cancel() function. To pause the computation, use the setPaused() function or one of the pause(), @@ -347,7 +369,7 @@ \sa takeResult(), result(), resultAt(), results(), resultCount(), isValid() */ -/* \fn template std::vector QFuture::takeResult() +/*! \fn template std::vector QFuture::takeResult() Call this function only if isValid() returns \c true, otherwise the behavior is undefined. This function takes the first result from @@ -369,12 +391,12 @@ \sa takeResults(), result(), results(), resultAt(), isValid() */ -/* \fn template std::vector QFuture::isValid() const +/*! \fn template bool QFuture::isValid() const - Returns true if a result or results can be accessed or taken from this - QFuture object. Returns false after the result was taken from the future. + Returns \c true if a result or results can be accessed or taken from this + QFuture object. Returns false after the result was taken from the future. - \sa takeResults(), takeResult(), result(), results(), resultAt() + \sa takeResults(), takeResult(), result(), results(), resultAt() */ /*! \fn template QFuture::const_iterator QFuture::begin() const