C++ Logo

std-proposals

Advanced search

[std-proposals] std::async_noexcept

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Tue, 7 Nov 2023 11:35:37 +0000
It would be useful to have in the standard library a function,
'async_noexcept', that works exactly like 'async', except that:
    (1) The invocation of 'async' never throws an exception (e.g.
std::system_error, std::bad_alloc)
    (2) The future object is always valid, even if 'async' threw, and
even if the spawned thread throws an exception

The way this would work, is that there would be an extra parameter to
indicate the default return value, and so if you had the following
thread entry point:

    bool SomeFunc(int, char, string&&) { return true; }

Then you'd use 'async_noexcept' as follows:

    std::async_noexcept( false, SomeFunc, 7, 'a', string("Monkey") );

I started writing the implementation of 'async_noexcept' today and I'm
currently using it in one of my desktop PC programs. Here's what I've
got so far:

#include <functional> // function
#include <future> // async, future, launch, promise
#include <utility> // forward
#include <type_traits> // decay, invoke_result
template<typename FunctorType, typename... Params>
[[nodiscard]]
std::future< std::invoke_result_t< std::decay_t<FunctorType>,
std::decay_t<Params>... > >
async_noexcept(
    std::invoke_result_t< std::decay_t<FunctorType>,
std::decay_t<Params>... > default_retval,
    std::launch policy,
    FunctorType &&f,
    Params&&... args) noexcept
{
    typedef std::invoke_result_t< std::decay_t<FunctorType>,
std::decay_t<Params>... > R;

    // The lambda on the next line is created on the stack, however
    // there are no captures, so it's OK to invoke the lambda after
    // it has gone out of scope (i.e. from another thread).
    auto const mylambda = [](R lambda_default_retval, FunctorType
&&lambda_f, std::decay_t<Params>... lambda_args) -> R
      {
        try
        {
          return std::forward<FunctorType>(lambda_f)( lambda_args... );
        }
        catch(...)
        {
          return lambda_default_retval;
        }
      };

    try
    {
        return std::async(
          static_cast<std::launch>(policy),
          mylambda,
          default_retval,
          std::forward<FunctorType>(f),
          std::forward<Params>(args)... );
    }
    catch(...)
    {
        std::promise<R> mypromise;
        std::future<R> myfuture = mypromise.get_future();
        mypromise.set_value(default_retval);
        return myfuture;
    }
}

Received on 2023-11-07 11:35:50