2) Calls a function f with arguments args according to a specific launch policy policy:

If the async flag is set (i.e. policy &std::launch::async!=0), then async executes the function f on a separate thread of execution as if spawned by std::thread(f, args...), except that if the function f returns a value or throws an exception, it is stored in the shared state accessible through the std::future that async returns to the caller.

If the deferred flag is set (i.e. policy &std::launch::deferred!=0), then async converts args... the same way as by std::thread constructor, but does not spawn a new thread of execution. Instead, lazy evaluation is performed: the first call to a non-timed wait function on the std::future that async returned to the caller will cause f(args...) to be executed in the current thread. The result or exception is placed in the shared state associated with the future and only then it is made ready. All further accesses to the same std::future will return the result immediately.

In any case, the call to std::asyncsynchronizes-with (as defined in std::memory_order) the call to f, and the completion of f is sequenced-before making the shared state ready. If the async policy is chosen, the associated thread completion synchronizes-with the successful return from the first function that is waiting on the shared state, or with the return of the last function that releases the shared state, whichever comes first.

The implementation may extend the behavior of the first overload of std::async by enabling additional (implementation-defined) bits in the default launch policy.

If the std::future obtained from std::async has temporary object lifetime (not moved or bound to a variable), the destructor of the std::future will block at the end of the full expression until the asynchronous operation completes, essentially code such as the following synchronous: