Title
[fund.ts.v3] `experimental::observer_ptr` should have more constexpr
Status
new
Section
[memory.observer.ptr.special]
Submitter
Jonathan Wakely

Created on 2025-07-14.00:00:00 last changed 4 days ago

Messages

Date: 2025-07-14.10:05:49

Proposed resolution:

This wording is relative to N4939.

  1. Modify [memory.syn] as indicated:
    
    #include <memory>
    
    namespace std {
      namespace experimental::inline fundamentals_v3 {
    
        // 8.2, Non-owning (observer) pointers
        template <class W> class observer_ptr;
    
        // 8.2.6, observer_ptr specialized algorithms
        template <class W>
        constexpr void swap(observer_ptr<W>&, observer_ptr<W>&) noexcept;
        template <class W>
        constexpr observer_ptr<W> make_observer(W*) noexcept;
        // (in)equality operators
        template <class W1, class W2>
        constexpr bool operator==(observer_ptr<W1>, observer_ptr<W2>);
    
        template <class W1, class W2>
        constexpr bool operator!=(observer_ptr<W1>, observer_ptr<W2>);
        template <class W>
        constexpr bool operator==(observer_ptr<W>, nullptr_t) noexcept;
        template <class W>
        constexpr bool operator!=(observer_ptr<W>, nullptr_t) noexcept;
        template <class W>
        constexpr bool operator==(nullptr_t, observer_ptr<W>) noexcept;
        template <class W>
        constexpr bool operator!=(nullptr_t, observer_ptr<W>) noexcept;
        // ordering operators
        template <class W1, class W2>
        constexpr bool operator<(observer_ptr<W1>, observer_ptr<W2>);
        template <class W1, class W2>
        constexpr bool operator>(observer_ptr<W1>, observer_ptr<W2>);
        template <class W1, class W2>
        constexpr bool operator<=(observer_ptr<W1>, observer_ptr<W2>);
        template <class W1, class W2>
        constexpr bool operator>=(observer_ptr<W1>, observer_ptr<W2>);
    
      } // namespace experimental::inline fundamentals_v3
    
      // 8.2.7, observer_ptr hash support
      template <class T> struct hash;
      template <class T> struct hash<experimental::observer_ptr<T>>;
    
    } // namespace std
    
  2. Modify [memory.observer.ptr.special] as indicated:
    
    template <class W>
      constexpr void swap(observer_ptr<W>& p1, observer_ptr<W>& p2) noexcept;
    
    -2- Effects: `p1.swap(p2)`.
    
    template <class W> constexpr observer_ptr<W> make_observer(W* p) noexcept;
    
    -4- Returns: observer_ptr<W>{p}.
    
    template <class W1, class W2>
      constexpr bool operator==(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -6- Returns: `p1.get() == p2.get()`.
    
    template <class W1, class W2>
      constexpr bool operator!=(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -8- Returns: `not (p1 == p2)`.
    
    template <class W>
      constexpr bool operator==(observer_ptr<W> p, nullptr_t) noexcept;
    template <class W>
      constexpr bool operator==(nullptr_t, observer_ptr<W> p) noexcept;
    
    -10- Returns: `not p`.
    
    template <class W>
      constexpr bool operator!=(observer_ptr<W> p, nullptr_t) noexcept;
    template <class W>
      constexpr bool operator!=(nullptr_t, observer_ptr<W> p) noexcept;
    
    -12- Returns: `(bool)p`.
    
    template <class W1, class W2>
      constexpr bool operator<(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -14- Returns: less<W3>()(p1.get(), p2.get()), where `W3` is the composite pointer type (C++20 §7) of `W1*` and `W2*`.
    
    template <class W1, class W2>
      constexpr bool operator>(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -16- Returns: p2 < p1.
    
    template <class W1, class W2>
      constexpr bool operator<=(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -16- Returns: not (p2 < p1).
    
    template <class W1, class W2>
      constexpr bool operator>=(observer_ptr<W1> p1, observer_ptr<W2> p2);
    
    -16- Returns: not (p1 < p2).
Date: 2025-07-15.11:24:13

In the Library Fundamentals TS, the `swap` overload, `make_observer_ptr` function, and comparisons for `observer_ptr` could be constexpr, but are not. The member `swap` is already constexpr in the TS, and the non-member `swap` is constexpr in libc++ but not the comparisons. The proposed resolution has been implemented and tested in libstdc++.

If we ever rebase the TS on a new C++ standard (or put `observer_ptr` into the standard) the comparisons should all be updated like so:


template <class W1, class W2>
constexpr bool operator==(observer_ptr<W1> p1, observer_ptr<W2> p2);
Returns: `p1.get() == p2.get()`.
bool operator!=(...);

template <class W>
constexpr bool operator==(observer_ptr<W> p, nullptr_t) noexcept;
bool operator==(...);
Returns: `not p`.
bool operator!=(...);
bool operator!=(...);

template <class W1, class W2>
constexpr bool operator<=>(observer_ptr<W1> p1, observer_ptr<W2> p2);
Returns: less<W3>compare_three_way()(p1.get(), p2.get()), where `W3` is the composite pointer type (C++20 §7) of `W1*` and `W2*`.
bool operator>(...);
bool operator<=(...);
bool operator>=(...);
History
Date User Action Args
2025-07-14 10:05:49adminsetmessages: + msg14897
2025-07-14 00:00:00admincreate