On Wed, Aug 23, 2023 at 8:01 AM Breno Guimarães <brenorg@gmail.com> wrote:
Perhaps a fair addition to the language is to allow RVO with slicing iff sizeof(Base) == sizeof(Derived):

struct LockedMutex : public std::mutex {
    LockedMutex() { lock(); }
};

std::mutex getLockedMutex() { return LockedMutex(); } // Hey, why not?

You'd have to explain whose destructor that code runs, and why.

  struct Animal { ~Animal(); };
  struct Cat : Animal { ~Cat(); };
  Animal getAnimal() { Cat c; return c; }
  int main() { Animal a = getAnimal(); }

Today this calls Cat(), Animal(Cat&&), ~Cat(), ~Animal().
I think you're proposing it would run Cat(), ~Animal(). Which is mismatched.
Or else this particular variation wouldn't compile — maybe we say "okay, in order to trigger the feature we must have sizeof(Base) == sizeof(Derived) and Derived has no non-defaulted destructor, and Derived has no non-inherited data members, and Derived has no direct bases other than Base, ..." But that's epicycles on top of epicycles, which is never a good sign. And even once the physical stuff works, we'll still have to explain to the object model why it's okay to construct a Cat and destroy only an Animal. (Admittedly the object model already has trouble with NRVO, so maybe this doesn't really make it worse. But it certainly doesn't help.)

("... and Derived is not polymorphic; and overload resolution on Base(Derived&&) finds some move constructor of Base, not anything else ...")

I'd rather have a feature designed to play well with the object model (a feature that lets me somehow "run code on a prvalue-in-flight", or simply mark a return statement to "force NRVO") than a physical hack like that. (And I think the majority of EWG would agree, if such a hack ever actually reached a vote: I think ultimately it wouldn't stand any real chance.)

my $.02,
–Arthur