Date: Wed, 29 May 2024 09:58:13 -0400
On Mon, May 27, 2024 at 7:55 PM Gašper Ažman <gasper.azman_at_[hidden]> wrote:
> Arthur,
>
> The whole reason to even have std::is_elide_v separate is because you
> can't necessarily change your own widget. Like, I have one called
> initializer_t, I want to use it as if it were std::elide, but I can't fix
> it to have the nested typedef, perhaps because I don't have write access.
>
You do? My understanding of Frederick's `std::elide` idea was that it would
be basically the same thing that I call "SCSE", i.e.:
https://godbolt.org/z/T7W3GW35h
template<class T, class F>
struct elide {
F lam_;
explicit elide(F lam) : lam_(lam) {}
operator T() const { return lam_(); }
};
elide(auto&& lam) -> elide<decltype(lam()), decltype(lam)>;
template<class T>
struct list {
template<class... Args> void emplace_back(Args&&...);
};
std::list<Immovable> v;
Immovable make_immovable();
v.emplace_back(elide([]() { return make_immovable(); }));
and then we have to postulate that there's an ImmovableAny like
https://godbolt.org/z/nh7ehcK9o
struct ImmovableAny {
template<class T> requires (!std::is_same_v<std::decay_t<T>,
ImmovableAny>)
ImmovableAny(T&&);
ImmovableAny(ImmovableAny&&) = delete;
};
that we want to emplace like this:
std::list<ImmovableAny> v;
ImmovableAny make_immovable();
v.emplace_back(elide([]() { return make_immovable(); }));
and then *the problem we're trying to solve* is that this will construct an
`ImmovableAny` holding an `elide`, rather than calling `elide::operator
ImmovableAny`. Frederick's proposed *solution* (which, as I said, IMO is
very bad) is that template type deduction should never deduce a (possibly
cvref-qualified) specialization of `elide`.
So you have code that uses a third-party `initializer_t` that acts just
like this `elide`? and since it's third-party you can't modify it, nor can
you rewrite it to match the seven-liner above? but you do want that
third-party `initializer_t` to share this template-type-deduction carveout
in the core language, because you want to use types like `ImmovableAny`?
I mean, I guess there's nothing *logically inconsistent* about any of that
scenario. It just *feels* like we've gone two or three levels beyond
realism at this point.
> Arthur,
>
> The whole reason to even have std::is_elide_v separate is because you
> can't necessarily change your own widget. Like, I have one called
> initializer_t, I want to use it as if it were std::elide, but I can't fix
> it to have the nested typedef, perhaps because I don't have write access.
>
You do? My understanding of Frederick's `std::elide` idea was that it would
be basically the same thing that I call "SCSE", i.e.:
https://godbolt.org/z/T7W3GW35h
template<class T, class F>
struct elide {
F lam_;
explicit elide(F lam) : lam_(lam) {}
operator T() const { return lam_(); }
};
elide(auto&& lam) -> elide<decltype(lam()), decltype(lam)>;
template<class T>
struct list {
template<class... Args> void emplace_back(Args&&...);
};
std::list<Immovable> v;
Immovable make_immovable();
v.emplace_back(elide([]() { return make_immovable(); }));
and then we have to postulate that there's an ImmovableAny like
https://godbolt.org/z/nh7ehcK9o
struct ImmovableAny {
template<class T> requires (!std::is_same_v<std::decay_t<T>,
ImmovableAny>)
ImmovableAny(T&&);
ImmovableAny(ImmovableAny&&) = delete;
};
that we want to emplace like this:
std::list<ImmovableAny> v;
ImmovableAny make_immovable();
v.emplace_back(elide([]() { return make_immovable(); }));
and then *the problem we're trying to solve* is that this will construct an
`ImmovableAny` holding an `elide`, rather than calling `elide::operator
ImmovableAny`. Frederick's proposed *solution* (which, as I said, IMO is
very bad) is that template type deduction should never deduce a (possibly
cvref-qualified) specialization of `elide`.
So you have code that uses a third-party `initializer_t` that acts just
like this `elide`? and since it's third-party you can't modify it, nor can
you rewrite it to match the seven-liner above? but you do want that
third-party `initializer_t` to share this template-type-deduction carveout
in the core language, because you want to use types like `ImmovableAny`?
I mean, I guess there's nothing *logically inconsistent* about any of that
scenario. It just *feels* like we've gone two or three levels beyond
realism at this point.
--- In general, the type author should be in control of their type's behavior, and users shouldn't be allowed to ODR-violate that type *directly*. The accepted way to "modify" a type's behavior is to wrap it in a different type — with a different name for ODR purposes — and apply all your new behaviors to that new type. Two examples: - P1144 would have permitted taking a third-party type that you can't modify (like boost::static_vector) and — not* directly warranting* it (which would violate ODR for functions like `vector<static_vector>::erase`) — but *wrapping* it in your own rule-of-zero type which you *can* warrant. [P2786 won't allow this.] - In 2023, LWG finally confirmed that ordinary programmers aren't allowed <https://github.com/cplusplus/draft/pull/6134> to specialize `allocator_traits` for their own types. The right place to customize the behavior of an allocator `A` is inside `A` itself, not inside `allocator_traits<A>`. If you don't own `A`, then you must wrap it in `B` and customize `B` instead. my $.02, Arthur
Received on 2024-05-29 13:58:28