diff --git a/xml/issue4015.xml b/xml/issue4015.xml index 508f00c1d8..2a544868ee 100644 --- a/xml/issue4015.xml +++ b/xml/issue4015.xml @@ -58,11 +58,743 @@ value and sets has_val to false; otherwise no effect.

+ +2023-11-26; Daniel provides wording +

+The proposed wording is considerably influenced by that of the specification of expected, but +attempts to reduce the amount of changes to not perfectly mimic it. Although "the contained value" is +a magic word of power it seemed feasible and simpler to use the new exposition-only member val +directly in some (but not all) places, usually involved with initializations. +

+Furthermore, I have only added "and sets has_val to true/false" +where either the Effects wording says "otherwise no effect" or in other cases if the postconditions +did not already say that indirectly. I also added extra mentioning of has_val changes in tables +where different cells had very different effects on that member (unless these cells specify postconditions), +to prevent misunderstanding. +

+This wording is relative to after application of the wording of LWG . +

+ +
    + +
  1. Modify , class template optional synopsis, as indicated:

    + +
    +
    +namespace std {
    +  template<class T>
    +  class optional {
    +  public:
    +    using value_type = T;
    +    […]
    +  private:
    +    bool has_val; // exposition only
    +    union {
    +      T val*val; // exposition only
    +    }
    +  };
    +  
    +  […]
    +}
    +
    +
    +
  2. + +
  3. Modify as indicated:

    + +
    +

    +-2- Member has_val indicates whether an optional<T> object contains a +valueWhen an optional<T> object contains a value, member val points to +the contained value. +

    +
    +
  4. + +
  5. Modify as indicated:

    + +
    +

    +[Drafting note: Normatively, this subclause doesn't require any changes, but I'm suggesting to replace +phrases of the form "[…]initializes the contained value with"] by "[…]initializes val with" +as we do in . I intentionally did not add extra +"and sets has_val to true/false" since those effects are already guaranteed by the postconditions] +

    +
    + +
    +
    +constexpr optional(const optional& rhs);
    +
    +
    +

    +-4- Effects: If rhs contains a value, direct-non-list-initializes +valthe contained value with *rhs.val. +

    +-5- Postconditions: rhs.has_value() == this->has_value(). +

    +[…] +

    +
    +
    +constexpr optional(optional&& rhs) noexcept(see below);
    +
    +
    +

    +-8- Constraints: […] +

    +-9- Effects: If rhs contains a value, direct-non-list-initializes +valthe contained value with std::move(*rhs.val). +rhs.has_value() is unchanged. +

    +-10- Postconditions: rhs.has_value() == this->has_value(). +

    +[…] +

    +
    +
    +template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);
    +
    +
    +

    +-13- Constraints: […] +

    +-14- Effects: Direct-non-list-initializes valthe contained value +with std::forward<Args>(args).... +

    +-15- Postconditions: *this contains a value. +

    +[…] +

    +
    +
    +template<class U, class... Args>
    +  constexpr explicit optional(in_place_t, initializer_list<U> il, Args&&... args);
    +
    +
    +

    +-18- Constraints: […] +

    +-19- Effects: Direct-non-list-initializes valthe contained value +with il, std::forward<Args>(args).... +

    +-20- Postconditions: *this contains a value. +

    +[…] +

    +
    +
    +template<class U = T> constexpr explicit(see below) optional(U&& v);
    +
    +
    +

    +-23- Constraints: […] +

    +-24- Effects: Direct-non-list-initializes valthe contained value +with std::forward<U>(v). +

    +-25- Postconditions: *this contains a value. +

    +[…] +

    +
    +
    +template<class U> constexpr explicit(see below) optional(const optional<U>& rhs);
    +
    +
    +

    +-28- Constraints: […] +

    +-29- Effects: If rhs contains a value, direct-non-list-initializes +valthe contained value with *rhs.val. +

    +-30- Postconditions: rhs.has_value() == this->has_value(). +

    +[…] +

    +
    +
    +template<class U> constexpr explicit(see below) optional(optional<U>&& rhs);
    +
    +
    +

    +-33- Constraints: […] +

    +-34- Effects: If rhs contains a value, direct-non-list-initializes +valthe contained value with +std::move(*rhs.val). rhs.has_value() is unchanged. +

    +-35- Postconditions: rhs.has_value() == this->has_value(). +

    +[…] +

    +
    +
    +
  6. + +
  7. Modify as indicated:

    + +
    +
    +constexpr ~optional();
    +
    +
    +

    +-1- Effects: If is_trivially_destructible_v<T> != true and *this contains a value, +calls val->val.T::~T(). +

    +
    +
    +
  8. + +
  9. Modify as indicated:

    + +
    +
    +constexpr optional<T>& operator=(nullopt_t) noexcept;
    +
    +
    +

    +-1- Effects: If *this contains a value, calls +val->val.T::~T() to destroy the contained +value and sets has_val to false; otherwise no effect. +

    +-2- Postconditions: *this does not contain a value. +

    +
    +
    +constexpr optional<T>& operator=(const optional& rhs);
    +
    +
    +

    +-4- Effects: See Table 58. +

    + + + + + + + + + + + + + + + + + + + + +
    Table 58 — optional::operator=(const optional&) effects [tab:optional.assign.copy]
    *this contains a value*this does not contain a value
    rhs contains a valueassigns *rhs.val to valthe contained valuedirect-non-list-initializes valthe contained value +with *rhs.val
    +and sets has_val to true +
    rhs does not contain a valuedestroys the contained value by calling val->val.T::~T()
    +and sets has_val to false +
    no effect
    +

    +-5- Postconditions: rhs.has_value() == this->has_value(). +

    +[…] +

    +
    +
    +constexpr optional<T>& operator=(optional&& rhs) noexcept(see below);
    +
    +
    +

    +-8- Constraints: […] +

    +-9- Effects: See Table 59. The result of the expression rhs.has_value() remains unchanged. +

    +-10- Postconditions: rhs.has_value() == this->has_value(). +

    +-11- Returns: *this. +

    + + + + + + + + + + + + + + + + + + + + +
    Table 59 — optional::operator=(optional&&) effects [tab:optional.assign.move]
    *this contains a value*this does not contain a value
    rhs contains a valueassigns std::move(*rhs.val) to valthe contained valuedirect-non-list-initializes valthe contained value with +std::move(*rhs.val) and sets has_val to true
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T()and sets has_val to false
    no effect
    +

    +-12- Remarks: […] +

    +-13- If any exception is thrown, the result of the expression this->has_value() remains +unchanged. If an exception is thrown during the call to T's move constructor, the state +of *rhs.valval is determined by the exception +safety guarantee of T's move constructor. If an exception is thrown during the call to +T's move assignment, the state of *valval +and *rhs.valval is determined by the exception +safety guarantee of T's move assignment. +

    +
    +
    +template<class U = T> constexpr optional<T>& operator=(U&& v);
    +
    +
    +

    +-14- Constraints: […] +

    +-15- Effects: If *this contains a value, assigns std::forward<U>(v) +to valthe contained value; otherwise direct-non-list-initializes +valthe contained value with std::forward<U>(v). +

    +-16- Postconditions: *this contains a value. +

    +-17- Returns: *this. +

    +-18- Remarks: If any exception is thrown, the result of the expression this->has_value() +remains unchanged. If an exception is thrown during the call to T's constructor, the state of +v is determined by the exception safety guarantee of T's constructor. If an exception +is thrown during the call to T's assignment, the state of val*val +and v is determined by the exception safety guarantee of T's assignment. +

    +
    +
    +template<class U> constexpr optional<T>& operator=(const optional<U>& rhs);
    +
    +
    +

    +-19- Constraints: […] +

    +-20- Effects: See Table 60. +

    + + + + + + + + + + + + + + + + + + + + +
    Table 60 — optional::operator=(const optional<U>&) effects [tab:optional.assign.copy.templ]
    *this contains a value*this does not contain a value
    rhs contains a valueassigns *rhs.val to valthe contained valuedirect-non-list-initializes valthe contained value +with *rhs.val and sets has_val to true
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T() and sets has_val to false
    no effect
    +

    +-21- Postconditions: rhs.has_value() == this->has_value(). +

    +-22- Returns: *this. +

    +-23- If any exception is thrown, the result of the expression this->has_value() remains +unchanged. If an exception is thrown during the call to T's constructor, the state of +*rhs.valval is determined by the exception safety +guarantee of T's constructor. If an exception is thrown during the call to T's +assignment, the state of val*val and +*rhs.valval is determined by the exception safety +guarantee of T's assignment. +

    +
    +
    +template<class U> constexpr optional<T>& operator=(optional<U>&& rhs);
    +
    +
    +

    +-24- Constraints: […] +

    +-25- Effects: See Table 61. The result of the expression rhs.has_value() remains unchanged.

    + + + + + + + + + + + + + + + + + + + + +
    Table 61 — optional::operator=(optional<U>&&) effects [tab:optional.assign.move.templ]
    *this contains a value*this does not contain a value
    rhs contains a valueassigns std::move(*rhs.val) to valthe contained valuedirect-non-list-initializes valthe contained value with
    +std::move(*rhs.val) and sets has_val to true
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T() and sets has_val to false
    no effect
    +

    +-26- Postconditions: rhs.has_value() == this->has_value(). +

    +-27- Returns: *this. +

    +-28- If any exception is thrown, the result of the expression this->has_value() remains +unchanged. If an exception is thrown during the call to T's constructor, the state of +*rhs.valval is determined by the exception safety +guarantee of T's constructor. If an exception is thrown during the call to T's +assignment, the state of val*val and +*rhs.valval is determined by the exception safety +guarantee of T's assignment. +

    +
    +
    +template<class... Args> constexpr T& emplace(Args&&... args);
    +
    +
    +

    +-29- Mandates: […] +

    +-30- Effects: Calls *this = nullopt. Then direct-non-list-initializes +valthe contained value with std::forward<Args>(args).... +

    +-31- Postconditions: *this contains a value. +

    +-32- Returns: valA reference to the new contained value. +

    +[…] +

    +-34- Remarks: If an exception is thrown during the call to T's constructor, *this +does not contain a value, and the previous val*val (if any) +has been destroyed. +

    +
    +
    +template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);
    +
    +
    +

    +-35- Constraints: […] +

    +-36- Effects: Calls *this = nullopt. Then direct-non-list-initializes +valthe contained value with il, std::forward<Args>(args).... +

    +-37- Postconditions: *this contains a value. +

    +-38- Returns: valA reference to the new contained value. +

    +[…] +

    +-40- Remarks: If an exception is thrown during the call to T's constructor, *this +does not contain a value, and the previous val*val (if any) +has been destroyed. +

    +
    +
    +
  10. + +
  11. Modify as indicated:

    + +
    +
    +constexpr void swap(optional& rhs) noexcept(see below);
    +
    +
    +

    +-1- Mandates: […] +

    +-2- Preconditions: […] +

    +-3- Effects: See Table 62. +

    + + + + + + + + + + + + + + + + + + + + +
    Table 62 — optional::swap(optional&) effects [tab:optional.swap]
    *this contains a value*this does not contain a value
    rhs contains a valuecalls swap(val*(*this), *rhs.val)direct-non-list-initializes valthe contained value of *this
    +with std::move(*rhs.val), followed by rhs.val.val->T::~T();
    +postcondition is that *this contains a value and rhs does
    +not contain a value
    rhs does not contain a valuedirect-non-list-initializes the contained value of rhs.val
    +with std::move(val*(*this)), followed by val.val->T::~T();
    +postcondition is that *this does not contain a value and rhs
    +contains a value
    no effect
    +

    +-4- Throws: […] +

    +-5- Remarks: […] +

    +-6- If any exception is thrown, the results of the expressions this->has_value() and +rhs.has_value() remain unchanged. If an exception is thrown during the call to function swap, +the state of val*val and +*rhs.valval is determined by the exception safety +guarantee of swap for lvalues of T. If an exception is thrown during the call to +T's move constructor, the state of val*val and +*rhs.valval is determined by the exception safety +guarantee of T's move constructor. +

    +

    +
    +
    +
  12. + +
  13. Modify as indicated:

    + +
    +
    +constexpr const T* operator->() const noexcept;
    +constexpr T* operator->() noexcept;
    +
    +
    +

    +-1- Preconditions: *this contains a value. +

    +-2- Returns: addressof(val)val. +

    +-3- […] +

    +
    +
    +constexpr const T& operator*() const & noexcept;
    +constexpr T& operator*() & noexcept;
    +
    +
    +

    +-4- Preconditions: *this contains a value. +

    +-5- Returns: val*val. +

    +-6- […] +

    +
    +
    +constexpr T&& operator*() && noexcept;
    +constexpr const T&& operator*() const && noexcept;
    +
    +
    +

    +-7- Preconditions: *this contains a value. +

    +-8- Effects: Equivalent to: return std::move(val*val); +

    +
    +
    +constexpr explicit operator bool() const noexcept;
    +
    +
    +

    +-9- Returns: true if and only if *this contains a value. +

    +-10- Remarks: This function is a constexpr function. +

    +
    +
    +constexpr bool has_value() const noexcept;
    +
    +
    +

    +-11- Returns: has_valtrue if and only if *this contains a value. +

    +-12- Remarks: These functions areThis function is a constexpr functions. +

    +
    +
    +constexpr const T& value() const &;
    +constexpr T& value() &;
    +
    +
    +

    +-13- Effects: Equivalent to: +

    +
    +return has_value() ? val*val : throw bad_optional_access();
    +
    +
    +
    +constexpr T&& value() &&;
    +constexpr const T&& value() const &&;
    +
    +
    +

    +-14- Effects: Equivalent to: +

    +
    +return has_value() ? std::move(val*val) : throw bad_optional_access();
    +
    +
    +
    +template<class U> constexpr T value_or(U&& v) const &;
    +
    +
    +

    +-15- Mandates: […] +

    +-16- Effects: Equivalent to: +

    +
    +return has_value() ? val**this : static_cast<T>(std::forward<U>(v));
    +
    +
    +
    +template<class U> constexpr T value_or(U&& v) &&;
    +
    +
    +

    +-17- Mandates: […] +

    +-18- Effects: Equivalent to: +

    +
    +return has_value() ? std::move(val**this) : static_cast<T>(std::forward<U>(v));
    +
    +
    +
    +
  14. + +
  15. Modify as indicated:

    + +
    +
    +template<class F> constexpr auto and_then(F&& f) &;
    +template<class F> constexpr auto and_then(F&& f) const &;
    +
    +
    +

    +-1- Let U be invoke_result_t<F, decltype((val)*val)>. +

    +-2- Mandates: […] +

    +-3- Effects: Equivalent to: +

    +
    +if (*this) {
    +  return invoke(std::forward<F>(f), val*val);
    +} else {
    +  return remove_cvref_t<U>();
    +}
    +
    +
    +
    +template<class F> constexpr auto and_then(F&& f) &&;
    +template<class F> constexpr auto and_then(F&& f) const &&;
    +
    +
    +

    +-4- Let U be invoke_result_t<F, decltype(std::move(val*val))>. +

    +-5- Mandates: […] +

    +-6- Effects: Equivalent to: +

    +
    +if (*this) {
    +  return invoke(std::forward<F>(f), std::move(val*val));
    +} else {
    +  return remove_cvref_t<U>();
    +}
    +
    +
    +
    +template<class F> constexpr auto transform(F&& f) &;
    +template<class F> constexpr auto transform(F&& f) const &;
    +
    +
    +

    +-7- Let U be remove_cv_t<invoke_result_t<F, decltype((val)*val)>>. +

    +-8- Mandates: U is a non-array object type other than in_place_t or nullopt_t. The declaration +

    +
    +U u(invoke(std::forward<F>(f), val*val));
    +
    +

    +is well-formed for some invented variable u. +

    +[…] +

    +-9- Returns: If *this contains a value, an optional<U> object whose contained value is +direct-non-list-initialized with invoke(std::forward<F>(f), val*val); otherwise, +optional<U>(). +

    +
    +
    +template<class F> constexpr auto transform(F&& f) &&;
    +template<class F> constexpr auto transform(F&& f) const &&;
    +
    +
    +

    +-10- Let U be remove_cv_t<invoke_result_t<F, decltype(std::move(val*val))>>. +

    +-11- Mandates: U is a non-array object type other than in_place_t or nullopt_t. The declaration +

    +
    +U u(invoke(std::forward<F>(f), std::move(val*val)));
    +
    +

    +is well-formed for some invented variable u. +

    +[…] +

    +-12- Returns: If *this contains a value, an optional<U> object whose contained value is +direct-non-list-initialized with invoke(std::forward<F>(f), std::move(val*val)); otherwise, +optional<U>(). +

    +
    +
    +
  16. + +
  17. Modify as indicated:

    + +
    +
    +constexpr void reset() noexcept;
    +
    +
    +

    +-1- Effects: If *this contains a value, calls val->val.T::~T() +to destroy the contained value and sets has_val to false; otherwise no effect. +

    +-2- Postconditions: *this does not contain a value. +

    +
    +
    +
  18. + +