This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4295. [fund.ts.v3] experimental::observer_ptr should have more constexpr

Section: 8.2.6 [fund.ts.v3::memory.observer.ptr.special] Status: New Submitter: Jonathan Wakely Opened: 2025-07-14 Last modified: 2025-07-14

Priority: Not Prioritized

View all issues with New status.

Discussion:

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 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>=(...);

Proposed resolution:

This wording is relative to N4939.

  1. Modify 8.1 [fund.ts.v3::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 8.2.6 [fund.ts.v3::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.