std::to_address()
should be SFINAE-friendlySection: 20.2.4 [pointer.conversion] Status: New Submitter: Peter Kasting Opened: 2024-03-13 Last modified: 2024-03-15
Priority: Not Prioritized
View all other issues in [pointer.conversion].
View all issues with New status.
Discussion:
LWG 3545 made std::pointer_traits
SFINAE-friendly.
However, std::to_address
is still not required to be SFINAE-friendly.
This requires callers who wish to accept both pointer-like and non-pointer-like
types to guard calls with a constraint that reimplements the core logic of
to_address
, such as the following:
template<typename T>
concept IsPointerLike = requires { typename std::pointer_traits<T>::pointer; }
|| requires (const T& t) { t.operator->(); };
Making to_address
not be SFINAE-friendly
was seen as desirable,
so std::contiguous_iterator
would produce a hard error for types marked with
contiguous_iterator_tag
that do not properly support to_address
.
Thus any fix should not regress that unless LWG explicitly decides to do so.
Also note that libc++'s current implementation of to_address
,
which is SFINAE-friendly,
does not produce such a hard error.
Proposed resolution:
This wording is relative to N4971.
Modify 20.2.4 [pointer.conversion] as indicated:
template<class Ptr> constexpr auto to_address(const Ptr& p) noexcept;
-?- Constraints: Either the expression
pointer_traits<Ptr>::to_address(p)
is well-formed (see 20.2.3.4 [pointer.traits.optmem]), or the expressionp.operator->()
is well-formed.-3- Returns:
pointer_traits<Ptr>::to_address(p)
if that expression is well-formed(see 20.2.3.4 [pointer.traits.optmem]), otherwiseto_address(p.operator->())
.
Modify 24.3.4.14 [iterator.concept.contiguous] as indicated:
-1- The
contiguous_iterator
concept provides a guarantee that the denoted elements are stored contiguously in memory.template<class I> concept contiguous_iterator = random_access_iterator<I> && derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> && is_lvalue_reference_v<iter_reference_t<I>> && same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> &&
requires(const I& i) { { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>; }std::same_as<decltype([] { return std::to_address(std::declval<I>()); }()), std::add_pointer_t<std::iter_reference_t<I>>>;
[The submitter welcomes less awkward alternatives to achieve the desired hard error for contiguous_iterator
.]