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.

4324. unique_ptr<void>::operator* is not SFINAE-friendly

Section: 20.3.1.3.5 [unique.ptr.single.observers] Status: New Submitter: Hewill Kang Opened: 2025-08-24 Last modified: 2025-08-26

Priority: Not Prioritized

View other active issues in [unique.ptr.single.observers].

View all other issues in [unique.ptr.single.observers].

View all issues with New status.

Discussion:

LWG 2762(i) added a conditional noexcept specification to unique_ptr::operator* to make it consistent with shared_ptr::operator*:

constexpr add_lvalue_reference_t<T> operator*() const noexcept(noexcept(*declval<pointer>()));

This unexpectedly makes unique_ptr<void>::operator* no longer SFINAE-friendly, for example:

#include <memory>

template<class T> concept dereferenceable = requires(T& t) { *t; };

static_assert( dereferenceable<int *>);
static_assert(!dereferenceable<void*>);

static_assert( dereferenceable<std::shared_ptr<int >>);
static_assert(!dereferenceable<std::shared_ptr<void>>);

static_assert( dereferenceable<std::unique_ptr<int >>);
static_assert( dereferenceable<std::unique_ptr<void>>); // hard error

Given that the standard intends for operator* of shared_ptr and unique_ptr to be SFINAE-friendly based on 20.3.2.2.6 [util.smartptr.shared.obs], regardless of the value of static_assert, it is reasonable to assume that there should be no hard error here.

Previous resolution [SUPERSEDED]:

This wording is relative to N5014.

  1. Modify 20.3.1.3.5 [unique.ptr.single.observers] as indicated:

    constexpr add_lvalue_reference_t<T> operator*() const noexcept(noexcept(*declval<pointer>())see below);
    

    -1- Mandates: reference_converts_from_temporary_v<add_lvalue_reference_t<T>, decltype(*declval<pointer>())> is false.

    -2- Preconditions: get() != nullptr is true.

    -3- Returns: *get().

    -?- Remarks:: The exception specification is equivalent to:

    !requires { *declval<pointer>(); } || requires { { *declval<pointer>() } noexcept; }
    

[2025-08-26; Reflector discussion]

During reflector triaging it had been pointed out that a better solution would be to constrain the operator* directly. The proposed wording has been updated to that effect.

Proposed resolution:

This wording is relative to N5014.

  1. Modify 20.3.1.3.5 [unique.ptr.single.observers] as indicated:

    constexpr add_lvalue_reference_t<T> operator*() const noexcept(noexcept(*declval<pointer>()));
    

    -?- Constraints: *declval<pointer>() is a well-formed expression.

    -1- Mandates: reference_converts_from_temporary_v<add_lvalue_reference_t<T>, decltype(*declval<pointer>())> is false.

    -2- Preconditions: get() != nullptr is true.

    -3- Returns: *get().