Date: Thu, 25 Sep 2025 07:52:46 +0200
> It would break lots, because we're not talking here about the built-in operator-> that you quoted; we're talking about the overloaded operator->.
Yeah sure, you'd also (or instead?) need to adjust the way [over.ref]
expands to the builtin -> operator.
Now thinking about it, it's probably "instead" because whether a
pointer is an rvalue is somewhat irrelevant. However, it's also
irrelevant whether an iterator or any other type with reference
semantics is an rvalue, so an operator-> that propagates value
category should presumably have an explicit opt-in.
> struct T {
> int fn() &;
> };
> struct Optional {
> T t_;
> const T* operator->() const { return &t_; }
> T* operator->() { return &t_; }
> };
> struct SharedPtr {
> T *p_;
> T *operator->() const { return p_; }
> };
> Optional getOptional();
> SharedPtr getSharedPtr();
> int main() {
> getOptional()->fn(); // getOptional() is a prvalue, and we'd like fn() not to be callable here
> getSharedPtr()->fn(); // getSharedPtr() is a prvalue, but we must continue to call fn() here; there's nothing wrong with this code
> }
>
> Now, we could at least give a (QoI) compiler warning if `expr->f()` on an rvalue `expr` invokes a non-const `operator->` member function. (Test cases here.) That seems tricky to implement, but maybe it's not so hard as I'm thinking.
> In fact, my P1144 Clang fork already gives a warning if `expr = rhs` on an rvalue `expr` invokes a non-const `operator=`, because that's almost always a bug.
There's no way that in your code, the compiler could tell if you're
working with a type that has reference semantics (like SharedPtr), so
I don't think any of this can be solved as QoI. I don't see how it
would be warning-worthy to call a non-const member function through
operator-> on an rvalue like getSharedPtr(). The value category of the
SharedPtr is irrelevant.
> getOptionalRef()->set(2);
> getSharedPtr()->set(2);
> getPointer()->set(2);
Code like this is totally fine.
With the benefit of hindsight, operator-> should have returned an
lvalue or rvalue reference rather than a pointer, exactly like
operator*. Then the author of the class could choose to propagate the
value category, only if that makes sense.
Yeah sure, you'd also (or instead?) need to adjust the way [over.ref]
expands to the builtin -> operator.
Now thinking about it, it's probably "instead" because whether a
pointer is an rvalue is somewhat irrelevant. However, it's also
irrelevant whether an iterator or any other type with reference
semantics is an rvalue, so an operator-> that propagates value
category should presumably have an explicit opt-in.
> struct T {
> int fn() &;
> };
> struct Optional {
> T t_;
> const T* operator->() const { return &t_; }
> T* operator->() { return &t_; }
> };
> struct SharedPtr {
> T *p_;
> T *operator->() const { return p_; }
> };
> Optional getOptional();
> SharedPtr getSharedPtr();
> int main() {
> getOptional()->fn(); // getOptional() is a prvalue, and we'd like fn() not to be callable here
> getSharedPtr()->fn(); // getSharedPtr() is a prvalue, but we must continue to call fn() here; there's nothing wrong with this code
> }
>
> Now, we could at least give a (QoI) compiler warning if `expr->f()` on an rvalue `expr` invokes a non-const `operator->` member function. (Test cases here.) That seems tricky to implement, but maybe it's not so hard as I'm thinking.
> In fact, my P1144 Clang fork already gives a warning if `expr = rhs` on an rvalue `expr` invokes a non-const `operator=`, because that's almost always a bug.
There's no way that in your code, the compiler could tell if you're
working with a type that has reference semantics (like SharedPtr), so
I don't think any of this can be solved as QoI. I don't see how it
would be warning-worthy to call a non-const member function through
operator-> on an rvalue like getSharedPtr(). The value category of the
SharedPtr is irrelevant.
> getOptionalRef()->set(2);
> getSharedPtr()->set(2);
> getPointer()->set(2);
Code like this is totally fine.
With the benefit of hindsight, operator-> should have returned an
lvalue or rvalue reference rather than a pointer, exactly like
operator*. Then the author of the class could choose to propagate the
value category, only if that makes sense.
Received on 2025-09-25 05:53:03