On Sun, 22 Sept 2024 at 19:12, Arthur O'Dwyer via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Sun, Sep 22, 2024 at 12:45 PM Jonathan Wakely via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Sun, 22 Sept 2024 at 17:21, Oliver Schädlich via Std-Proposals <std-proposals@lists.isocpp.org> 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.