When a thread activates an asynchronous provider (e.g., a tt(std::async)) then
the return value of the asynchronously called function becomes available in
its activating thread through a tt(std::future) object. The
tt(future) object cannot be used by another thread. If this is required (e.g.,
see this chapter's final section) the tt(future) object must be converted to a
    hi(shared_future)tt(std::shared_future) object. 

Before using the class tt(std::shared_future) the tthi(future) header file
must be included.

Once a tt(shared_future) object is available, its tt(get) member (see below)
can repeatedly be called to retrieve the results of the original tt(future)
object. This is illustrated by the next small example:
    verbinclude(-ns4 //code examples/sharedfuture.cc)
    In lines 9 and 10 the tt(promise's) results are retrieved multiple times,
but having obtained the tt(shared_future) in line 7, the original tt(future)
object no longer has an associated shared state. Therefore, when another
attempt is made (in line 13) to obtain the tt(shared_future), a em(no
associated state) exception is thrown and the program aborts.

However, multiple copies of tt(shared_future) objects may co-exist.  When
multiple copies of tt(shared_future) objects exist (e.g. in different
threads), the results of the associated asynchronous task are made ready
(become available) at exactly the same moment in time.

The relationship between the classes tt(future) and tt(shared_future)
resembles the relationship between the classes tt(unique_ptr) and
tt(shared_ptr): there can only be one instance of a tt(unique_pointer),
pointing to data, whereas there can be many instances of a tt(shared_pointer),
each pointing to the same data. 

The effect of calling any member of a tt(shared_future) object for which
tt(valid() == false) other than the destructor, the move-assignment operator,
or tt(valid) is undefined.

The class tt(shared_future) supports the following constructors:
    itemization(
    itt(shared_future() noexcept)
        quote(an empty tt(shared_future) object is constructed that does not
            refer to shared results. After using this constructor the object's
            tt(valid) member returns tt(false).)

    itt(shared_future(shared_future const &other))
        quote(a tt(shared_future) object is constructed that refers to the
            same results as tt(other) (if any). After using this constructor
            the object's tt(valid) member returns the same value as
            tt(other.valid()).)

    itt(shared_future(shared_future<Result> &&tmp) noexcept)
        quote( Effects: move constructs a shared_future object that refers to
            the results that were originally referred to by tt(tmp) (if
            any). After using this constructor the object's tt(valid) member
            returns the same value as tt(tmp.valid()) returned prior to the
            constructor invocation, and tt(tmp.valid()) returns tt(false).)

    itt(shared_future(future<Result> &&tmp) noexcept)
        quote( Effects: move constructs a shared_future object that refers to
            the results that were originally referred to by tt(tmp) (if
            any). After using this constructor the object's tt(valid) member
            returns the same value as tt(tmp.valid()) returned prior to the
            constructor invocation, and tt(tmp.valid()) returns tt(false).)
    )

The class's destructor destroys the tt(shared_future) object for which it is
called. If the object for which the destructor is called is the last
tt(shared_future) object, and no tt(std::promise) or
tt(std::packaged_task) is associated with the results associated
with the current object, then the results are also destroyed.

Here are the members of the class tt(std::shared_future):
    itemization(
    ittq(shared_future& operator=(shared_future &&tmp))
       (The move assignment operator releases the current object's shared
        results, and move assigns tt(tmp's) results to the current
        object. After calling the move assignment operator the current
        object's tt(valid) member returns the same value as tt(tmp.valid())
        returned prior to the invocation of the move assignment operator, and
        tt(tmp.valid()) returns tt(false);)

    ittq(shared_future& operator=(shared_future const &rhs))
       (The assignment operator releases the current object's shared results,
        and tt(rhs)'s results are shared with the current object. After
        calling the assignment operator the current object's tt(valid) member
        returns the same value as tt(tmp.valid());)

    ittq(Result const &shared_future::get() const)
       ((Specializations for tt(shared_future<Result &>) and
        tt(shared_future<void>) are also available). This member waits until
        the shared results are available, and subsequently returns tt(Result
        const &). Note that access to the data stored in tt(Results), accessed
        through tt(get) is not synchronized. It is the responsibility of the
        programmer to avoid race conditions when accessing tt(Result's)
        data. If tt(Result) holds an exception, it is thrown when tt(get) is
        called;)

    ittq(bool valid() const)
       (Returns tt(true) if the current object refers to shared
            results;)

    ittq(void wait() const)
       (Blocks until shared results are available (i.e., the associated
        asynchronous task has produced results);)

    ittq(future_status wait_for(const chrono::duration<Rep, Period>& rel_time)
            const)
       ((The template types tt(Rep) and tt(Period) normally are derived by the
        compiler from the actual tt(rel_time) specification.) If the shared
        results contain a deferred function (cf. section ref(ASYNC)) nothing
        happens. Otherwise tt(wait_for) blocks until the results of the
        associated asynchronous task has produced results, or until the
        relative time specified by tt(rel_time) has expired. The member
        returns 
           itemization( 
           itt(future_status::deferred) if the shared results contain a
            deferred function; itt(future_status::ready) if the shared results
            are available;
           itt(future_status::timeout) if the function is returning because
            the amount of time specified by tt(rel_time) has expired;)
        )

    ittq(future_status wait_until(const chrono::time_point<Clock, Duration>&
            abs_time) const)
       ((The template types tt(Clock) and tt(Duration) normally are derived by
        the compiler from the actual tt(abs_time) specification.) If the
        shared results contain a deferred function nothing happens. Otherwise
        tt(wait_until) blocks until the shared results are available or until
        the point in time specified by tt(abs_time) has expired. Possible
        return values are:
           itemization(
            itt(future_status::deferred) if the shared results contain a
                deferred function;
            itt(future_status::ready) if the shared results are available;
            itt(future_status::timeout) if the function is returning because
                the point in time specified by tt(abs_time) has expired. 
            )
        )
    )
