C++ Logo

std-proposals

Advanced search

[std-proposals] Possible Flaw/Hole in the type system

From: Andre Kostur <andre_at_[hidden]>
Date: Wed, 24 Sep 2025 20:45:28 -0700
I'm trying to determine if this is actually a defect in the language,
or am I missing something?:

The short version is that one can call deleted rvalue-qualified member
functions on an object within a temporary std::optional via
operator->. Consider:

#include <optional>
#include <cstdint>

class Thing {
public:
  uint32_t fn() & { return 0; }
  uint32_t fn() && = delete;
};

std::optional<Thing> accessor() {
  return std::optional{Thing{}};
}

int main() {
  accessor().value().fn(); // Fails (correctly) to compile
  accessor()->fn(); // Compiles, but shouldn't?
  (*accessor()).fn(); // Fails (correctly?) to compile
}

A little longer description: I stumbled on this in some code where
I've got a class which can return iterators/pointers into private
members of the class (represented by "Thing::fn"). Since this is a
dangerous operation, I wanted to make it harder to trigger by
rvalue-qualifying the function and deleting it so that one can't
invoke it on a temporary object. Now there's some other function
which returns an optional Thing by value. If I directly call fn on
that temporary via either value() or operator*, the compiler correctly
recognizes that I'm attempting to call fn() on an rvalue and
recognizes that it's a deleted function. But, if I call via
operator-> (line 31), there's a raw pointer in the evaluation sequence
where the compiler loses the "rvalue-ness" and allows me to call fn().
(Ignoring the nullopt case)

I'm using std::optional as the example as that's where I saw this, but
this applies to any type T that has an operator->. The returned raw
pointer is what opens up this possibility.

Received on 2025-09-25 03:45:40