Date: Mon, 16 Dec 2024 00:04:51 +0800
>
> The array has size 3 *and capacity 3*, whereas the inplace_vector has
> size 3 *and capacity unknown*.
Sorry, in this case, I think inplace_vector will have a capacity of *3,*
and its current size is 3.
IMO, no it would not.
> Notice that what you have there is equivalent in effect to:
> constexpr auto v = []<size_t... Is>(index_sequence<Is...>) {
> size_t v[] = {Is...};
> auto [begin, end] = std::ranges::remove(v, 42);
> return std::inplace_vector<size_t, *sizeof...(Is)*>(v, begin);
> }(std::make_index_sequence<N>{});
I don't want to specify T and N explicitly.
The reason I give this example is because the final size of inplace_vector
is always smaller than N as it will remove some elements, which means the
capacity of inplace_vector *can* be N, which can be obtained via CTAD.
If I currently have an array and I want to convert it to an
inplace_vector, with CATD we just can:
array<T, N> arr{...};
inplace_vector v{from_range, arr}; // With capacity and size N
Otherwise, we must:
array<T, N> arr{...};
inplace_vector<tuple_size_v<deltype(arr)>, deltype(arr)::value_type> v
(arr.begin(), arr.end());
So the CTAD is an improvement in my opinion.
Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> 於 2024年7月29日 週一 上午5:20寫道:
> On Sun, Jul 28, 2024 at 10:20 AM Hewill Kang via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>>
>> Quoting the original paper’s description
>> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0843r14.html#Deduction-guides>
>> for deduction guides for std::inplace_vector: "*Unlike the other
>> containers, inplace_vector** does not have any deduction guides because
>> there is no case in which it would be possible to deduce the second
>> template argument, the capacity, from the initializer.*"
>>
>> However, I found that in some cases it is possible to enable CTAD for
>> std::inplace_vector, for example when we accept a std::array or std::span
>> :
>>
>> template<class T, size_t N>
>> inplace_vector(from_range_t, const std::array<T, N>&) ->
>> inplace_vector<T, N>; // new CTAD
>> Then we can:
>>
>> std::inplace_vector v{std::from_range, std::array{1, 2, 3}};
>>
>
> The array has size 3 *and capacity 3*, whereas the inplace_vector has
> size 3 *and capacity unknown*.
> You're asking why the (initial) size of an inplace_vector might ever be
> different from its capacity... but that's literally the reason that
> inplace_vector exists! If you want a container whose size is always equal
> to its capacity, you could just use `array` directly.
>
> I think this makes meta-programming more user-friendly and convenient, for
>> example, converting index_sequence into inplace_vector and then applying
>> the algorithm in <algorithm>:
>>
>> constexpr inplace_vector v = []<size_t... Is>(index_sequence<Is...>) {
>> inplace_vector v{from_range, array{Is...}};
>> auto [begin, end] = ranges::remove(v, 42);
>> v.erase(begin, end);
>> return v;
>> }(std::make_index_sequence<N>{});
>> Would it be valuable for inplace_vector to introduce std::array or
>> std::span-specific CTADs?
>>
>
> IMO, no it would not.
>
> Notice that what you have there is equivalent in effect to:
>
> constexpr auto v = []<size_t... Is>(index_sequence<Is...>) {
> size_t v[] = {Is...};
> auto [begin, end] = std::ranges::remove(v, 42);
> return std::inplace_vector<size_t, *sizeof...(Is)*>(v, begin);
> }(std::make_index_sequence<N>{});
>
> `*sizeof...(Is)*` is almost certainly the *wrong* capacity, there. Either
> you're planning to add more elements to it (so you need more capacity), or
> you're not (in which case you should use a capacity equal to the *final*
> size, not the size *before* the remove).
>
> I also have a vague sense that since inplace_vector is expensive to
> move-construct, we really don't want to encourage people to create
> inplace_vectors without thinking about capacity — and then have to move
> them into the "proper" type later on. We can get away with that for types
> like `shared_ptr<U>` and `unique_ptr<U>`, where converting to the correct
> type is O(1). But for `inplace_vector<T, M>`, converting to
> `inplace_vector<T, N>` is an O(M) operation.
>
> HTH,
> Arthur
>
> The array has size 3 *and capacity 3*, whereas the inplace_vector has
> size 3 *and capacity unknown*.
Sorry, in this case, I think inplace_vector will have a capacity of *3,*
and its current size is 3.
IMO, no it would not.
> Notice that what you have there is equivalent in effect to:
> constexpr auto v = []<size_t... Is>(index_sequence<Is...>) {
> size_t v[] = {Is...};
> auto [begin, end] = std::ranges::remove(v, 42);
> return std::inplace_vector<size_t, *sizeof...(Is)*>(v, begin);
> }(std::make_index_sequence<N>{});
I don't want to specify T and N explicitly.
The reason I give this example is because the final size of inplace_vector
is always smaller than N as it will remove some elements, which means the
capacity of inplace_vector *can* be N, which can be obtained via CTAD.
If I currently have an array and I want to convert it to an
inplace_vector, with CATD we just can:
array<T, N> arr{...};
inplace_vector v{from_range, arr}; // With capacity and size N
Otherwise, we must:
array<T, N> arr{...};
inplace_vector<tuple_size_v<deltype(arr)>, deltype(arr)::value_type> v
(arr.begin(), arr.end());
So the CTAD is an improvement in my opinion.
Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> 於 2024年7月29日 週一 上午5:20寫道:
> On Sun, Jul 28, 2024 at 10:20 AM Hewill Kang via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>>
>> Quoting the original paper’s description
>> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0843r14.html#Deduction-guides>
>> for deduction guides for std::inplace_vector: "*Unlike the other
>> containers, inplace_vector** does not have any deduction guides because
>> there is no case in which it would be possible to deduce the second
>> template argument, the capacity, from the initializer.*"
>>
>> However, I found that in some cases it is possible to enable CTAD for
>> std::inplace_vector, for example when we accept a std::array or std::span
>> :
>>
>> template<class T, size_t N>
>> inplace_vector(from_range_t, const std::array<T, N>&) ->
>> inplace_vector<T, N>; // new CTAD
>> Then we can:
>>
>> std::inplace_vector v{std::from_range, std::array{1, 2, 3}};
>>
>
> The array has size 3 *and capacity 3*, whereas the inplace_vector has
> size 3 *and capacity unknown*.
> You're asking why the (initial) size of an inplace_vector might ever be
> different from its capacity... but that's literally the reason that
> inplace_vector exists! If you want a container whose size is always equal
> to its capacity, you could just use `array` directly.
>
> I think this makes meta-programming more user-friendly and convenient, for
>> example, converting index_sequence into inplace_vector and then applying
>> the algorithm in <algorithm>:
>>
>> constexpr inplace_vector v = []<size_t... Is>(index_sequence<Is...>) {
>> inplace_vector v{from_range, array{Is...}};
>> auto [begin, end] = ranges::remove(v, 42);
>> v.erase(begin, end);
>> return v;
>> }(std::make_index_sequence<N>{});
>> Would it be valuable for inplace_vector to introduce std::array or
>> std::span-specific CTADs?
>>
>
> IMO, no it would not.
>
> Notice that what you have there is equivalent in effect to:
>
> constexpr auto v = []<size_t... Is>(index_sequence<Is...>) {
> size_t v[] = {Is...};
> auto [begin, end] = std::ranges::remove(v, 42);
> return std::inplace_vector<size_t, *sizeof...(Is)*>(v, begin);
> }(std::make_index_sequence<N>{});
>
> `*sizeof...(Is)*` is almost certainly the *wrong* capacity, there. Either
> you're planning to add more elements to it (so you need more capacity), or
> you're not (in which case you should use a capacity equal to the *final*
> size, not the size *before* the remove).
>
> I also have a vague sense that since inplace_vector is expensive to
> move-construct, we really don't want to encourage people to create
> inplace_vectors without thinking about capacity — and then have to move
> them into the "proper" type later on. We can get away with that for types
> like `shared_ptr<U>` and `unique_ptr<U>`, where converting to the correct
> type is O(1). But for `inplace_vector<T, M>`, converting to
> `inplace_vector<T, N>` is an O(M) operation.
>
> HTH,
> Arthur
>
Received on 2024-12-15 16:05:10