On Tue, Mar 4, 2025 at 3:03 PM Zhihao Yuan <
zy@miator.net> wrote:
If someone is designing their own container,
a simple rvalue reference to array is usually
enough
template<size_t N>
vector(T (&&arr)[N]);
// use
vector v1({2, 4}); vector v2({std::make_unique<int>(1), std::make_unique<int>(2)});
I would be skeptical of that, though.
(1) That disables the "normal" way of constructing from a bag of elements:
vector v1 = {2, 4}; // no longer works
We are used to it, but you already know the pitfalls.
vector v1 = {a.begin(), a.end()};
Well, that's an anti-pitfall in the case of std::vector: CTAD will see that you're giving it a bag of elements of type `decltype(a)::iterator`, and rightly put them into a `vector<decltype(a)::iterator>`.
Remember, curlies mean "sequence of elements of an aggregate, or something pretending to be an aggregate (such as a product type, container, or span)."
std::vector erroneously lacks `explicit` on its multi-argument ctors, which leads to the non-CTAD pitfall
std::vector<int> v2 = {"1", "2"}; // boom, UB
but in that case using CTAD would actually eliminate the UB (by constructing a vector<const char*> instead).
The thing is, if you make your non-template VectorOfInt such that
VectorOfInt v = {1, 2};
doesn't compile, then it's going to suck. I don't think you can get away with that level of user-hostility in container design.
(2) That disables P2752 static-storage optimization:
vector v1({
#embed "large-file.dat" // compiles, but blows your stack at runtime
});
[...] In fact I recall you had opinions of some kind about applying P2752 to array literals too, which I shot down as scope creep; do you think it's possible to fix the codegen in #2 with a core-language change? The problem I see is that you're explicitly wanting to move-out-of the elements of `arr`, so it can't possibly go into static storage, right?
Yes and no. If a class knew the input is not meant
for modification, a matrix for example, then it can
take T const (&&arr)[N], in which case the
semantics is identical to initializer_list, i.e., binding
a unique reference to a backing array and implying
that the data is immutable. And then a generic
container can choose whether to add const
programmatically, if that's what they want
- There is no "backing array" (no P2752 treatment — again, I'll take the blame for this, but it's a fact); there's just a huge temporary on the stack.
- IIUC there is no "implying that the data is immutable," because can't the callee still const_cast the pointer? Or are the elements of temporary arrays actually const objects, such that it's UB to modify them? I'm like 70% sure they're not actually const objects.
–Arthur