C++ Logo

std-proposals

Advanced search

Re: [std-proposals] p3039r1 proxy temporary objects

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sun, 22 Feb 2026 17:07:37 -0500
On Sat, Feb 21, 2026 at 3:44 AM Jonathan Wakely <cxx_at_[hidden]> wrote:

> On Fri, 20 Feb 2026, 19:46 Arthur O'Dwyer via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> On Fri, Feb 20, 2026 at 1:39 PM Marcin Jaczewski via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> Paper suggests rewriting `ptr->meber` by `(*ptr).member`.
>>>
>>> But this creates an interesting case, new `->` created this way will
>>> have capabilities impossible compared to manually written `->`.
>>>
>>
>> Yes, and P3039R1
>> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3039r1.pdf>
>> mentions that it does [...]
>> [...]
>> Informally, yes, of course. P3039's adding rewrite rules for `->` is
>> exactly analogous to how C++20 added rewrite rules for `!=`. It doesn't
>> mean that defining your own `operator!=` is somehow morally bad at this
>> point, but it does mean that we expect defining your own `operator!=` to
>> become much rarer, and certainly unidiomatic in modern C++. However,
>> because of the billions of lines of code out there that do define their own
>> `operator!=`, it wouldn't be sensible to try to "push" anyone off of it
>> (e.g. by deprecating the syntax or anything like that). We can afford to
>> let the newer cleaner style displace the older more verbose style in its
>> own natural time.
>>
>
> For contiguous iterators (and any other iterators that want to work with
> std::to_address) the rewrite is undefined for a past-the-end iterator.
>

My understanding is that P3039 does *not* propose to rewrite any explicit
member-function-syntax call to `operator->`, such as:
    T *p = sptr.operator->();
into:
    T *p = &*sptr;

Right now, std::to_address() is defined in terms of
<http://www.eel.is/c++draft/pointer.conversion> such an explicit
member-function-syntax call to `sptr.operator->()`. So, any "fancy pointer"
or "smart pointer" will not be able to take advantage of this new feature;
they'll basically have to keep providing a user-defined `operator->()`
member function — or else specialize `pointer_traits` for their type (which
IMO they really shouldn't do, no more than they should specialize
iterator_traits or allocator_traits).

It seems lucky, and coincidental, that smart pointers and fancy pointers
are precisely those things where the value category of the thing doesn't
affect the value category of its referent: `sptr->x` and
`std::move(sptr)->x` should probably always have the same value category.

C++20 fuddles this up a little bit by conflating "contiguous iterators"
with "fancy pointers" — making `std::to_address()` the blessed way to
extract a past-the-end pointer from a past-the-end contiguous iterator. The
writer of a contiguous iterator will need to support std::to_address(),
which means supporting member-function-call syntax for `it.operator->()`,
which means not getting to use the rewrite feature for contiguous
iterators. This is Too Bad; but, unless I've missed something in spelling
it out in this paragraph:
- it doesn't seem too horrible, and
- IMO if we want to fix the contiguous-iterator-cast-to-pointer issue, we
would do better to revisit std::to_address and *do better* this time around
(e.g. just allow it to use `static_cast<T*>(it)` when that's well-formed,
and/or give it a Ranges-inspired customization point such as `it.base()` or
`it.to_pointer()`). Letting the current messiness of `std::to_address`
interfere with the current cleanliness of P3039 would be letting the tail
wagging the dog.

P3039 §6.6
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p3039r1.pdf> says
"20.2.4 [pointer.conversion] specifies to_address in terms of calling
p.operator->(), *so some thought will need to be put in there on what to
do.*" IMO the thing to do there is *nothing, for now*.
§6.6 already gives *nothing, for now*, as option (1), and characterizes the
outcome reasonably accurately:

> 1 and 2 feel like the wrong approach – they would mean that *authors of
> iterator types still need to define their own operator->*, or they must
> specialize some class template (if we agree that the current semantics with
> regard to iterators are correct), or they must overload to_address and we
> make that a customization point found by ADL.

I would insert the word "contiguous" before "iterator types," and I would
say that 1 feels like exactly the *right* approach.

P.S. — P3039 claims that "The following standard types can be used to
instantiate `pointer_traits`: [...] `span`," before pointing out correctly
that pointer_traits<span<T>> is nonsensical and doesn't work. This makes me
wonder: Why do the authors of P3039 think that `span` can be used to
instantiate `pointer_traits`? Who's teaching that? Certainly a `span` is
not a pointer — it's not even dereferenceable. If this is implied by
something in the actual paper Standard, we should probably fix that thing
ASAP.

–Arthur

Received on 2026-02-22 22:07:51