On Fri, 6 May 2022 at 09:55, Sébastien Bini <sebastien.bini@gmail.com> wrote:
> You'll need a relocate_wrapper type that can be (possibly implicitly) constructed from a callee-destroy prvalue, and that releases that value (by relocation to a prvalue) on request. So you call either push_back(relocate_wrapper(reloc x)), or relocate_back(reloc x).

This is similar to what is in the proposal: std::reloc_wrapper (page 24, https://github.com/SebastienBini/cpp-relocation-proposal/blob/main/relocation.pdf). You can relocate an object inside it, check if it has an object, and relocate it out. The problem is then that you need to perform two relocations (one inside the wrapper, one from the wrapper to the container).

Yes, that looks about right. The double-relocation can easily be elided, especially if we give the compiler permission to do so as a behavior-affecting optimization (i.e., above and beyond as-if).

Also, if no one sees a point of having non-default base-or-member initialisers in operator reloc member function, and that its source object is already destructed once the function body is reached, what would be wrong with this operator reloc?

struct T : B
{
    M data;

    /*
     * operator reloc returns a new instance.
     * actual relocation (base-class and data-member relocations) happen before the function body is called (as if by =default).
     * The function body only serves to make some adjustments, like fixing self-references.
     * 'this' pointer in reloc function body points to the newly constructed instance.
     * The source object is considered destructed and is no longer usable, that's why it does not appear as a parameter.
     * It is not possible to provide custom base-or-member-initializer.
     */
    operator reloc()
    {
        data.self = *this; // fix self-references here
    }
};

The problem is: what if data is const? Then it will not be possible to modify data.self in the function body. So I think you would need to be able to write:

operator reloc(T&& rhs)
    : data([&] { M data = std::move(rhs.data); data.self = *this; return data; }())
{}

By providing a base-or-member-initializer for data, you indicate that rhs.data should be destroyed once that initializer completes. This scheme can handle everything short of relocate-only const self-referential data members (since it has to use move-and-destroy, not relocation proper), but those are esoteric enough to not bother supporting (the user can just drop const in that case).