Thank you for clarifying.

On Mon, Oct 10, 2022 at 3:08 PM Edward Catmur <ecatmur@googlemail.com> wrote:
Oh, sorry - special member function. Copy/move/relocate constructors and assignment operators, and destructor; the Seven. I'm not counting other constructors (not even the default constructor) as those don't maintain invariants (though they may establish them) - a class without any of the seven SMFs can't claim to maintain any invariants, so std::decompose should be safe on it. The rules would be that when calling std::decompose on a prvalue of class type:

* if the class has any non-empty potentially overlapping direct subobjects (i.e., virtual bases or anonymous union members, but not EBO bases and [[no_unique_address]] members), then std::decompose is ill-formed
* otherwise, if it has any user-declared (not declared as defaulted) SMFs, or if it has any private direct subobjects, then std::decompose can only be called by members of the class and its friends
* otherwise, if it has any protected direct subobjects, std::decompose can only be called by members of the class, its friends, and its derived classes
* otherwise, std::decompose can be called from anywhere

Hmm, should be safe enough. Requiring the same access level as member functions if there is any user-declared SMF was the missing piece.

It is a rather atypical set of rules though. But I am okay with proposing that.
 
And, wrt. structured binding of an object e of class type E,

* if std::tuple_size<E>::value is well-formed, the tuple-like protocol is invoked to perform recursive destructuring if e is prvalue and `get_all` is found, else binding;
* otherwise, if e is prvalue and neither E nor any of its base classes has any user-declared SMFs, data member destructuring is performed: the lifetime of e and its bases (but not the lifetime of its data members) is ended and the identifiers name the data members individually (as prvalue, if the data member is not ref-qualified)
* otherwise, binding to data members occurs as at present and the identifiers name the data members as xvalue or lvalue

 In the second case, all data members must be from the same class and have public access (just like data-member binding protocol in today's structured bindings).

Other than that, we should be good!