Date: Sat, 21 Feb 2026 08:44:35 +0000
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, in §6:
>
> Simply removing the operator-> definition from classes could possibly
>> cause a different member function to be invoked. Specifically *if the
>> operator* that is chosen returns an rvalue reference* and we are
>> invoking a member function that has been both lvalue and rvalue reference
>> qualified: using operator-> would cause the lvalue qualified form to be
>> invoked but using operator* would cause the rvalue qualified form to be
>> invoked. This may cause subtle behaviour changes.
>
>
> However, I do see that §6.4 erroneously lists `optional` as one of the
> types that "have an operator-> that is identical to what the rewrite would
> accomplish." In fact, `optional` is one of the poster-child types that are
> intended to become more powerful with the rewrite.
>
> // https://godbolt.org/z/ah5jEjsvP
>
> optional<S> f();
>
> void use(int&); // #1
> void use(int&&); // #2
>
> int main() {
> use(f()->m); // calls #1; P3039 will change this to call #2
> use((*f()).m); // calls #2
> }
>
> Actually, *the reference implementation on Godbolt gets this example
> wrong*, so maybe this effect was unintended too (although I'm not sure
> how to square that with the quotation from §6, which seems to indicate that
> the authors were very much aware of this effect).
>
> Consider example:
>> ```
>> const auto& foo = ptr->member;
>> ```
>> and `ptr` that has a `*` returning proxy value.
>> With this rewrite, the lifetime of the proxy object will be expanded
>> to the lifetime of the `foo` reference.
>>
>
> Yes, that's another good example.
>
> maybe we should discourage of further use of user defined `->` operator?
>
>
> 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.
std::to_address(vec.end()) is valid, and works ok if operator-> returns a
pointer. But the rewritten form would use *vec.end() which is undefined.
So for some iterator types you will still need a user-provided operator->,
or will need to specialize std::pointer_traits::to_address instead.
> –Arthur
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/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, in §6:
>
> Simply removing the operator-> definition from classes could possibly
>> cause a different member function to be invoked. Specifically *if the
>> operator* that is chosen returns an rvalue reference* and we are
>> invoking a member function that has been both lvalue and rvalue reference
>> qualified: using operator-> would cause the lvalue qualified form to be
>> invoked but using operator* would cause the rvalue qualified form to be
>> invoked. This may cause subtle behaviour changes.
>
>
> However, I do see that §6.4 erroneously lists `optional` as one of the
> types that "have an operator-> that is identical to what the rewrite would
> accomplish." In fact, `optional` is one of the poster-child types that are
> intended to become more powerful with the rewrite.
>
> // https://godbolt.org/z/ah5jEjsvP
>
> optional<S> f();
>
> void use(int&); // #1
> void use(int&&); // #2
>
> int main() {
> use(f()->m); // calls #1; P3039 will change this to call #2
> use((*f()).m); // calls #2
> }
>
> Actually, *the reference implementation on Godbolt gets this example
> wrong*, so maybe this effect was unintended too (although I'm not sure
> how to square that with the quotation from §6, which seems to indicate that
> the authors were very much aware of this effect).
>
> Consider example:
>> ```
>> const auto& foo = ptr->member;
>> ```
>> and `ptr` that has a `*` returning proxy value.
>> With this rewrite, the lifetime of the proxy object will be expanded
>> to the lifetime of the `foo` reference.
>>
>
> Yes, that's another good example.
>
> maybe we should discourage of further use of user defined `->` operator?
>
>
> 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.
std::to_address(vec.end()) is valid, and works ok if operator-> returns a
pointer. But the rewritten form would use *vec.end() which is undefined.
So for some iterator types you will still need a user-provided operator->,
or will need to specialize std::pointer_traits::to_address instead.
> –Arthur
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2026-02-21 08:44:52
