diff --git a/xml/issue4015.xml b/xml/issue4015.xml index 7935f4a3fb..77c9978ee1 100644 --- a/xml/issue4015.xml +++ b/xml/issue4015.xml @@ -820,9 +820,7 @@ The rest of the proposed resolution is unchanged, so that edit was made in-place below, instead of as a new resolution that supersedes the old one.

- - - +

This wording is relative to .

@@ -1562,6 +1560,828 @@ to destroy the contained value; otherwise no effect. + + +
+ +2025-11-03; Tomasz tweaks proposed resolution +

+Updated converting constructor and assigments to use `operator*()` +directly, required to correctly support optional<T&>. +Also update corresponding constructor in specialization. +

+ + + + +

+This wording is relative to . +

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

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

    + +
    +

    +-1- + +When its member val is active +(), +an instance of optional<T> is said to +contain a value, and val is referred to as its +contained value. + + +An object of type optional<T> at any given time either +contains a value or does not contain a value. +When an object of type optional<T> contains a value, +it means that an object of type T, +referred to as the +An +optional object's +contained value +contained value, +is nested within () the optional object. + +When an object of type optional<T> +is contextually converted to bool, +the conversion returns `true` if the object contains a value; +otherwise the conversion returns `false`. + +

    +

    + +-2- When an optional<T> object contains a value, +member val +points to the contained value. + +

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

    + +
    +
    +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.operator*(). +

    +-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).operator*(). 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; 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
    +
    rhs does not contain a valuedestroys the contained value by calling val->val.T::~T()
    +
    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)
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T()
    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 states state of *valval +and *rhs.valval are 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 states state of val*val +and v are 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.operator*() to valthe contained valuedirect-non-list-initializes valthe contained value +with *rhs.operator*()
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T()
    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 states state of val*val and +*rhs.valval are 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).operator*() to valthe contained valuedirect-non-list-initializes valthe contained value with
    +*std::move(rhs).operator*()
    rhs does not contain a valuedestroys the contained value by calling
    +val->val.T::~T()
    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 states state of val*val and +*rhs.valval are 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 states state of val*val and +*rhs.valval are 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: true if and only if *this contains a value. +

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

    +
    +
    +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; otherwise no effect. +

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

    +
    +
    +
  18. + +
  19. Modify as indicated:

    + +
    +template<class U>
    +  constexpr explicit(!is_convertible_v<U&, T&>)
    +  optional(optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, U&>);
    +
    +
    +

    +-8- Constraints: […] +

    +-9- Effects: Equivalent to: +

    +  if (rhs.has_value()) convert-ref-init-val(*rhs.operator*());
    +
    +

    +-10- Remarks: […] +

    + +
    +template<class U>
    +  constexpr explicit(!is_convertible_v<const U&, T&>)
    +  optional(const optional<U>& rhs) noexcept(is_nothrow_constructible_v<T&, const U&>);
    +
    +
    +

    +-11- Constraints: […] +

    +-12- Effects: Equivalent to: +

    +  if (rhs.has_value()) convert-ref-init-val(*rhs.operator*());
    +
    +

    +-13- Remarks: […] +

    + +
    +template<class U>
    +  constexpr explicit(!is_convertible_v<U, T&>)
    +  optional(optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, U>);
    +
    +
    +

    +-14- Constraints: […] +

    +-15- Effects: Equivalent to: +

    +  if (rhs.has_value()) convert-ref-init-val(*std::move(rhs).operator*());
    +
    +

    +-16- Remarks: […] +

    + +
    +template<class U>
    +  constexpr explicit(!is_convertible_v<const U, T&>)
    +  optional(const optional<U>&& rhs) noexcept(is_nothrow_constructible_v<T&, const U>);
    +
    +
    +

    +-17- Constraints: […] +

    +-18- Effects: Equivalent to: +

    +  if (rhs.has_value()) convert-ref-init-val(*std::move(rhs).operator*());
    +
    +

    +-19- Remarks: […] +

    +
  20. +
diff --git a/xml/issue4316.xml b/xml/issue4316.xml index 982fac7a74..c8343ff4ee 100644 --- a/xml/issue4316.xml +++ b/xml/issue4316.xml @@ -147,12 +147,11 @@ This wording is relative to .

--1- For value `x` of type `info`, and prvalue constant expression `X` that computes the -reflection held by `x`, let TARG-SPLICE(x) be: +-1- Let TARG-SPLICE(x) be:

    -
  • -1.1- template [: X :] if `is_template(x)` is `true`, otherwise
  • -
  • -1.2- typename [: X :] if `is_type(x)` is `true`, otherwise
  • -
  • -1.3- ([: X :])
  • +
  • -1.1- template [: x :] if `is_template(x)` is `true`, otherwise
  • +
  • -1.2- typename [: x :] if `is_type(x)` is `true`, otherwise
  • +
  • -1.3- ([: x :])

@@ -168,7 +167,7 @@ sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order.

--2- Returns: `true` if Z<TARG-SPLICE([:Args:])...> is a valid template-id +-2- Returns: `true` if Z<TARG-SPLICE([:Args:])...> is a valid template-id () that does not name a function whose type contains an undeduced placeholder type. Otherwise, `false`.

@@ -177,7 +176,7 @@ Otherwise, `false`. in `arguments` represents a construct usable as a template argument ().

--4- [Note: If forming Z<TARG-SPLICE([:Args:])...> +-4- [Note: If forming Z<TARG-SPLICE([:Args:])...> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

@@ -193,12 +192,12 @@ sequence of prvalue constant expressions that compute the reflections held by the elements of `arguments`, in order.

--6- Returns: Z<TARG-SPLICE([:Args:])...>.

+-6- Returns: Z<TARG-SPLICE([:Args:])...>.

-7- Throws: `meta::exception` unless `can_substitute(templ, arguments)` is `true`.

--8- [Note: If forming Z<TARG-SPLICE([:Args:])...> +-8- [Note: If forming Z<TARG-SPLICE([:Args:])...> leads to a failure outside of the immediate context, the program is ill-formed. — end note]

diff --git a/xml/issue4432.xml b/xml/issue4432.xml index fbe59a755e..7641e339eb 100644 --- a/xml/issue4432.xml +++ b/xml/issue4432.xml @@ -4,7 +4,7 @@ Clarify element initialization for <tt>meta::reflect_constant_array</tt>
- +
Tomasz KamiƄski 27 Oct 2025 @@ -20,16 +20,15 @@ It is not clear what ei is when proxy references are involved. Clarify copy-initialization vs. direct-initialization use The initialization of P uses copy-initialization but the Mandates clause uses direct-initialization.

- - +

This wording is relative to .

    -
  1. Modify as indicated:

    +
  2. Modify as indicated:

     template<ranges::input_range R>
    @@ -52,6 +51,47 @@ where eiiti is an iterat
     
+
+ + + +

+This wording is relative to . +

+ +
    + +
  1. Modify as indicated:

    + +
    +template<ranges::input_range R>
    +  consteval info reflect_constant_array(R&& r);
    +
    +
    +

    -8- Let T be ranges::range_value_t<R> +and ei be static_cast<T>(*iti), +where iti is an iterator to the ith element of `r`. +

    +

    -9- Mandates: + T is a structural type (), + is_constructible_v<T, ranges::range_reference_t<R>> is true, and + is_copy_constructible_v<T> is true + T satisfies copy_constructible.

    +

    -10- Let V be the pack of values of type `info` of the same size as r, +where the ith element is reflect_constant(ei), +where ei is an iterator to the ith element of r. +

    +

    […]

    +

    -13- Throws: Any exception thrown by the evaluation of any ei, or +`meta::exception` unlessif evaluation of any reflect_constant(eei) +would exit via an exception +is a constant subexpression for every element `e` of `r`.

    +
    +
  2. +
+
+ +