std::experi...al::when_all(3)
π NAME π
std::experimental::when_all β literally std::experimental::when_all, bestie, the name tells you the whole story β¨
So this page lives in the C++ Standard Library (concurrency TS corner of it, iykyk) and it's all about that when_all life. Buckle up π
β¨ SYNOPSIS β¨
Okay so first things first β where does this even live?
Defined in header <experimental/future>
And here are the two overloads, in all their glory π
template< class InputIt >
auto when_all( InputIt first, InputIt last ) (1)
(concurrency TS)
-> future<std::vector<typename
std::iterator_traits<InputIt>::value_type>>;
template< class... Futures >
auto when_all( Futures&&... futures ) (2)
(concurrency TS)
-> future<std::tuple<std::decay_t<Futures>...>>;
Both of these are concurrency TS, in case the little (concurrency TS) tag wasn't loud enough π
π¦ What it actually does π¦
The whole vibe: you're creating a future object that becomes ready when all of the input futures and shared_futures become ready. All of them. Every last one. Group-project energy but, like, the one time it actually works π«Ά
β οΈ Real talk though: the behavior is undefined if any input future or shared_future is invalid. Not "undefined" as in "kinda weird", undefined as in do not do this. Periodt. π
Let me break it down more precisely, because you deserve the specifics:
Let Sequence be std::vector<typename std::iterator_traits<InputIt>::value_type> for (1), and std::tuple<std::decay_t<Futures>...> for (2). This function template creates a shared state containing Sequence and returns a future referring to that shared state.
- Every input future is moved into the corresponding object in the
Sequencein the shared state. - Every input shared_future is copied to the corresponding object in the
Sequencein the shared state. - The order of the objects in the
Sequencematches the order of the arguments. No shuffling, no vibes-based reordering, just in-order πΈ
π§ Overload resolution tea π§
1) This one does not participate in overload resolution unless InputIt's value type (i.e., typename std::iterator_traits<InputIt>::value_type) is a std::experimental::future or a std::experimental::shared_future.
2) This one does not participate in overload resolution unless every argument is either a (possibly cv-qualified) std::experimental::shared_future or a cv-unqualified std::experimental::future.
And here's the formally-formal version, for the syllabus nerds π (affectionate): for every type Fn in Futures, either std::remove_reference_t<Fn> is std::experimental::future<Rn>, or std::decay_t<Fn> is std::experimental::shared_future<Rn>.
π After the call π
This part is important, don't skip it:
- Every input future is no longer valid after this call π
- Every input shared_future remains valid π
Shared futures stay iconic, futures get consumed. That's the deal. π
π RETURN VALUE π
You get a future referring to the shared state that the call created. That future is always valid(), and it becomes ready when all of the input futures and shared_futures of the call are ready. Like a little readiness committee β
1) If the range is empty (i.e., first == last), the returned future contains an empty vector and is ready immediately β no waiting, instant slay β¨
2) If there are no arguments supplied, a future<std::tuple<>> is returned, and it is immediately ready. Zero arguments, zero problems, still valid π
π₯ Quick recap so it's locked in:when_allwaits for everything, moves futures, copies shared_futures, keeps your argument order, and gives you back afuturethat's alwaysvalid(). Invalid inputs = undefined behavior = please don't π
Okay that's the whole page, bestie β sourced from http://cppreference.com, dated 2024.06.10, and yes this is the std::experi...al::when_all(3) manual page, abridged-name-and-all ππ«Ά go forth and await your futures π
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms