C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::elide

From: Gašper Ažman <gasper.azman_at_[hidden]>
Date: Thu, 30 May 2024 16:55:27 +0100
The transparent conversion is useful because I have classes that are
*only* constructible from an elider - a named one. It's sort of like
saying that you only have std::in_place_type constructors but you
didn't care to make them variadic.

A lot of these classes *forward* their construction argument further
until it gets to where it actually needs to construct an object. This
matters when you've got expression templates that construct some
immovable tree of stuff at the end. If I have a component that
understands std::elide as an elider, but doesn't understand my elider
as an elider, I can still just construct std::elide from my elider
directly instead of having to rewrap in a lambda; and vice versa.

The only reason I think having std::elide in the library would be to
have a common vocabulary type that's better than std::in_place_type +
variadic forwarding of arguments.

On Thu, May 30, 2024 at 4:35 PM Arthur O'Dwyer
<arthur.j.odwyer_at_[hidden]> wrote:
>
> On Thu, May 30, 2024 at 11:14 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> On Thu, May 30, 2024 at 1:26 PM Gašper Ažman wrote:
>> >
>> > Both call a function to generate the returned type. Why
>> > can't an elider *be that function* directly? That way I can
>> > nest them either way and it still works.
>>
>> I have made the following two additions:
>> template<typename NestedF, typename... NestedParams>
>> constexpr decltype(auto) operator()(NestedF &&fN, NestedParams&&... argsN)
>> {
>> return forward<NestedF>(fN)( forward<NestedParams>(argsN)... );
>> }
>
>
> IIUC, this isn't right; what you want here is simply
> // https://godbolt.org/z/7he9b6GW6
>
> constexpr operator R()
> noexcept(noexcept(apply(static_cast<F_ref>(f),std::move(args_tuple))))
> {
> return apply( static_cast<F_ref>(f), std::move(args_tuple) );
> }
>
> constexpr R operator()()
> noexcept(noexcept(apply(static_cast<F_ref>(f),std::move(args_tuple))))
> {
> return *this;
> }
>
> as well as the const-qualified versions of those.
> The idea, IIUC, is to make the following code work.
> We suppose that the codebase already has their own `std::elide`-alike — which, btw, isn't even a seven-liner; it's now a five-liner.
>
> template<class F>
> struct SCSE {
> F f_;
> operator decltype(f_())() const { return f_(); }
> };
>
> Then we have these two calls working already:
>
> ocs8.emplace(std::elide([]{ return counting_semaphore<8>(5); }));
> ocs8.emplace(SCSE([]{ return counting_semaphore<8>(5); }));
>
> and Gasper is asking for this call to work as well:
>
> ocs8.emplace(SCSE(std::elide([]{ return counting_semaphore<8>(5); }))); // Gasper's request, IIUC
>
> Adding the `operator()` gets us that. Although, I still don't see why we want SCSE to be constructible from std::elide. I don't see how this helps with "interop." What's a scenario where I'd already have a `std::elide` object — whose sole purpose is to be treated like a `T` — and, instead of treating it like a `T`, I'm going to try to construct an `SCSE` out of it? That seems wrong. An `SCSE` expects a callable `C`, and so my `std::elide` should implicitly convert to `C` iff `T=C`, but otherwise it should stay aloof, IMHO. I don't see a concrete scenario where I'd want to be cavalier about the meaning of `elide` — like, "Please convert to `T` if you can, or otherwise convert to `SCSE`." Those are two different "parts of speech," IMO.
>
> (But, just to be clear, I consider this all academic, because the STL should not have `std::elide`.)
>
> –Arthur

Received on 2024-05-30 15:55:41