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 unownedstring(string_view) — "dangerous" in doing heap-allocation of something previously heap-avoidantspan<int,3>(span<int,2>) — "dangerous" in messing with the span's number of elementsThe last of these is already "taken" by span's explicit constructor. So if we addedspan<int,3>(span<const int,3>) — "dangerous" in removing const-qualification from the elementsthen we'd have two different dimensions of "danger," both expressed by explicit conversion. Suppose I'm doingauto 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?