https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95349
--- Comment #11 from Richard Biener <rguenth at gcc dot gnu.org> --- (In reply to Ed Catmur from comment #9) > (In reply to Jonathan Wakely from comment #4) > > I don't know the answer, and I don't know why it's useful to try this > > anyway. > > If I'm reading P0593 correctly (I may not be), this would be a valid > implementation of start_lifetime_as: > > template<class T> > inline T* start_lifetime_as(void* p) { > std::byte storage[sizeof(T)]; > std::memcpy(storage, p, sizeof(T)); > auto q = new (p) std::byte[sizeof(T)]; > std::memcpy(q, storage, sizeof(T)); > auto t = reinterpret_cast<T*>(q); > return std::launder(t); > } > > But this has the same issue: https://godbolt.org/z/YYtciP I think there is no way to pun the dynamic type of an object without altering its current storage representation. You can do punning via a union but that wouldn't change its effective type. Note that for C++ types you can apply memcpy to the placement new is not needed since object re-use terminates lifetime of the previous object and starts lifetime of a new one. This means that your example can be simplified to template<class T> inline T* start_lifetime_as(void* p) { return reinterpret_cast<T*>(q); } easily showing why that cannot be the intention. Note that while your example performs memcpy dances you are probably after a solution that elides all generated code? Note that I do not belive making your examples work as you intend is possible in an actual implementation without sacrifying all type-based alias analysis.