Date: Sun, 22 Sep 2024 20:14:08 +0100
On Sun, 22 Sept 2024 at 19:12, Arthur O'Dwyer via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Sun, Sep 22, 2024 at 12:45 PM Jonathan Wakely via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Sun, 22 Sept 2024 at 17:21, Oliver Schädlich via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> Maybe the opposite direction as explicit would make also sense.
>>>
>> I would prefer if that doesn't work.
>>
>
> Me too. Two things occur to me:
>
> (1) We permit this:
> using P = T*;
> const T *p;
> T *q = P(p);
> but that's only because a functional-style cast *on primitive types* can
> be interpreted as a const_cast or reinterpret_cast.
> On class types, a functional-style cast is really intended to be like a
> static_cast; and you can't do static_cast<P>(p).
>
> (2) We reserve explicit constructors for conversions that are physically
> meaningful but "dangerous" in some way, e.g.
> shared_ptr<T>(T*) — "dangerous" in taking ownership of something
> previously unowned
> string(string_view) — "dangerous" in doing heap-allocation of
> something previously heap-avoidant
> span<int,3>(span<int,2>) — "dangerous" in messing with the span's
> number of elements
> The last of these is already "taken" by span's explicit constructor. So if
> we added
> span<int,3>(span<const int,3>) — "dangerous" in removing
> const-qualification from the elements
> then we'd have two different dimensions of "danger," both expressed by
> explicit conversion. Suppose I'm doing
> auto sp = span<int,3>(otherspan);
> That's an explicit conversion, so I'm opting in to "danger"; but did I
> think I was opting into the buffer-overflow kind of danger, or the
> modifying-a-const-object kind of danger?
>
I can also imagine code something like:
auto make_span(range auto&& r) { return span<ranges::range_value_t<X>>(r); }
where the intent is to create a span from a range, but would also become an
unintentional "cast away const" function given span<const T>, if that could
be converted to span<T> explicitly.
There are better ways to write this function, but somebody could easily
write this and not realise it had a problem. Casting away const should be a
cast, not just a constructor. It's not the same, but this gives me
auto_ptr(auto_ptr&) vibes.
std-proposals_at_[hidden]> wrote:
> On Sun, Sep 22, 2024 at 12:45 PM Jonathan Wakely via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Sun, 22 Sept 2024 at 17:21, Oliver Schädlich via Std-Proposals <
>> std-proposals_at_[hidden]> wrote:
>>
>>> Maybe the opposite direction as explicit would make also sense.
>>>
>> I would prefer if that doesn't work.
>>
>
> Me too. Two things occur to me:
>
> (1) We permit this:
> using P = T*;
> const T *p;
> T *q = P(p);
> but that's only because a functional-style cast *on primitive types* can
> be interpreted as a const_cast or reinterpret_cast.
> On class types, a functional-style cast is really intended to be like a
> static_cast; and you can't do static_cast<P>(p).
>
> (2) We reserve explicit constructors for conversions that are physically
> meaningful but "dangerous" in some way, e.g.
> shared_ptr<T>(T*) — "dangerous" in taking ownership of something
> previously unowned
> string(string_view) — "dangerous" in doing heap-allocation of
> something previously heap-avoidant
> span<int,3>(span<int,2>) — "dangerous" in messing with the span's
> number of elements
> The last of these is already "taken" by span's explicit constructor. So if
> we added
> span<int,3>(span<const int,3>) — "dangerous" in removing
> const-qualification from the elements
> then we'd have two different dimensions of "danger," both expressed by
> explicit conversion. Suppose I'm doing
> auto sp = span<int,3>(otherspan);
> That's an explicit conversion, so I'm opting in to "danger"; but did I
> think I was opting into the buffer-overflow kind of danger, or the
> modifying-a-const-object kind of danger?
>
I can also imagine code something like:
auto make_span(range auto&& r) { return span<ranges::range_value_t<X>>(r); }
where the intent is to create a span from a range, but would also become an
unintentional "cast away const" function given span<const T>, if that could
be converted to span<T> explicitly.
There are better ways to write this function, but somebody could easily
write this and not realise it had a problem. Casting away const should be a
cast, not just a constructor. It's not the same, but this gives me
auto_ptr(auto_ptr&) vibes.
Received on 2024-09-22 19:15:27