This paper proposes a resolution to C++17 CD comment GB 62, which addresses
operations on shared_future
which have wide contracts.
1. GB 62
There is an implicit precondition on mostshared_future
operations thatvalid() == true
, 30.6.7p3. The list of exempted functions seems copied directly from classfuture
, and would also include copy operations forshared_future
s, which are copyable. Similarly, this would be a wide contract that cannot throw, so those members would be markednoexcept
.
2. SG1 and LEWG Response to GB 62
SG1 agreed with the proposed wording in the NB comment for shared_future
.
They felt the move constructor should also be added for the list in future
as well. There was unanimous consent to forward this paper to LEWG for design
review. LEWG reviewed it and sent it to LWG.
3. LWG Feedback
LWG made the following changes:
-
Rejected the addition of the constructors from the pre-condition whitelist (as the precondition has no meaning before the object is constructed).
-
Added a note clarifying that it is valid to copy from a future for which
valid()
isfalse
.
There was unanimous consent in LWG to move this paper at the Issaquah 2016 Friday plenary.
4. Proposed Wording
The proposed changes are relative to [N4604], the Committee Draft for C++17.
4.1. Changes to shared_future
Apply the following changes to 30.6.7 [futures.shared_future] paragraph 3:
The effect of calling any member function other than the destructor, the move-assignment operator, the copy-assignment operator, orvalid
on ashared_future
object for whichvalid()
isfalse
is undefined. [ Note: It is valid to copy or move from ashared_future
object for whichvalid()
isfalse
— end note ] [ Note: Implementations are encouraged to detect this case and throw an object of typefuture_error
with an error condition offuture_errc::no_state
. — end note ]
Apply the following changes to the class synopsis for shared_future
in
30.6.7 [futures.shared_future]:
namespace std { template <class R> class shared_future { public: shared_future() noexcept; shared_future(const shared_future& rhs) noexcept; shared_future(future<R>&&) noexcept; shared_future(shared_future&& rhs) noexcept; ~shared_future(); shared_future& operator=(const shared_future& rhs) noexcept; shared_future& operator=(shared_future&& rhs) noexcept; // retrieving the value see below get() const; // functions to check state bool valid() const noexcept; void wait() const; template <class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const; template <class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const; }; }
Apply the following changes to the definition of shared_future
's copy
constructor in 30.6.7 [futures.shared_future]:
shared_future(const shared_future& rhs) noexcept;Effects: Constructs a
shared_future
object that refers to the same shared state asrhs
(if any).Postcondition:
valid()
returns the same value asrhs.valid()
.
Apply the following changes to the definition of shared_future
's copy
assignment operator in 30.6.7 [futures.shared_future]:
shared_future& operator=(const shared_future& rhs) noexcept;Effects:
Releases any shared state (30.6.4);
assigns the contents of
rhs
to*this
. [ Note: As a result,*this
refers to the same shared state asrhs
(if any). — end note ]Postconditions:
valid() == rhs.valid()
.
4.2. Changes to future
Apply the following changes to 30.6.6 [futures.unique_future] paragraph 3:
The effect of calling any member function other than the destructor, the move-assignment operator, orvalid
on afuture
object for whichvalid()
isfalse
is undefined. [ Note: It is valid to move from afuture
object for whichvalid() == false
— end note ]
4.3. Acknowledgements
Thanks to Jonathan Wakely for assisting with the wording.