I've read a few Q/A about std::launder (What is the purpose of std::launder?, Does this really break strict-aliasing rules?, std::launder reachability rules), but am still unclear whether I am using it correctly in my specific use-case.  The following is what I am trying to achieve:
struct Base {
    ...
};
struct Derived : Base {
    ...
};
// Declare a buffer
alignas(std::max_align_t) char buffer[2000];
// Populate the buffer using placement-new
*reinterpret_cast<size_t*>(&buffer[0]) = sizeof(Derived);
Derived *d = new (&buffer[2 * sizeof(std::max_align_t)]) Derived();
*reinterpret_cast<Base**>(&buffer[sizeof(std::max_align_t)]) = static_cast<Base*>(d);
// Extract values from the buffer
size_t s = *reinterpret_cast<size_t*  >(&buffer[0]);
Base  *b = *reinterpret_cast<Base**   >(&buffer[sizeof(std::max_align_t)]);
       d = *reinterpret_cast<Derived**>(&buffer[sizeof(std::max_align_t) * 2]);
My inclination is that the following is the appropriate way to std::launder the above statements to ensure they all result in defined behavior per the standard:
// Populate the buffer using placement-new
*std::launder(reinterpret_cast<size_t*>(&buffer[0])) = sizeof(Derived);
Derived *d = new (&buffer[2 * sizeof(std::max_align_t)]) Derived();
*std::launder(reinterpret_cast<Base**>(&buffer[sizeof(std::max_align_t)])) = static_cast<Base*>(d);
// Extract values from the buffer
size_t s = *std::launder(reinterpret_cast<size_t*  >(&buffer[0]));
Base  *b = *std::launder(reinterpret_cast<Base**   >(&buffer[sizeof(std::max_align_t)]));
       d = *std::launder(reinterpret_cast<Derived**>(&buffer[sizeof(std::max_align_t) * 2]));
Is the above the appropriate usage of std::launder?  Do I have to placement-new the size_t and Base* members prior to assigning to them?  Do I have to std::launder the size_t and Base* members at all?
