On Sat, Mar 18, 2023 at 5:26 AM Jens Maurer <jens.maurer@gmx.net> wrote:
Would an interface like

template<class ... Ts>
std::tuple<Ts * ...> allocate_arrays( decltype(std::void_t<Ts>, std::size_t>)... );

help most of the use-cases?  If someone wants construction,
the std::uninitialized_* algorithms are at their service.

FWIW, I think so too; except that I would wrap it in a node-handle-esque RAII type. `allocate_arrays` knows exactly how the return value needs to be cleaned up, so it should return a type that expresses that to the caller. The caller should be able to call `.release()` on that return value in order to claim "I'll do the cleanup manually"... or, even more likely IMHO, the caller shouldn't be able to do that, because the caller shouldn't be permitted to know how the arrays were allocated nor how to clean them up. That should be an implementation detail which is left completely up to the implementation.

This implementation-detail business raises a new question: Suppose I ask for 1 int16, 1 int64, and 3 int32s. Should the implementation be required to allocate exactly
i16 (pad48) i64 i32 i32 i32
or should it be permitted to allocate e.g.
i32 i32 i32 i16 (pad16) i64
instead? I tentatively suggest that the latter should not be permitted — because one of the use-cases for this thing is the "we know where you live" optimization in make_shared, and that optimization works only if the location of the i64 can be computed from the location of the i16 plus some pointer math. If the second pointer in your returned std::tuple<Ts*...> isn't mechanically computable from the first pointer, and so on, then the thing isn't useful. This suggests that std::tuple<Ts*...> is the wrong return type, per the guideline "Make illegal states unrepresentable": it spends many extra CPU registers (maybe even spilling to the stack) in order to communicate information that the caller can compute themselves and/or doesn't want to compute in the first place.
But I don't know what a "better" return type would look like. :)

 
(The std::uninitialized_* algorithms seem to deal in pointers-to-T
even when pointing to not-yet-constructed memory.)

Yes; <off-topic> and that's the right choice.
https://quuxplusone.github.io/blog/2018/06/08/raw-memory-and-t-star/#notice-that-when-we-call-index-t
</off-topic>

Cheers,
Arthur