C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::construct<T>

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Tue, 3 Dec 2024 17:34:22 +0100
wt., 3 gru 2024 o 16:49 Gašper Ažman <gasper.azman_at_[hidden]> napisał(a):
>
> Jonathan Wakeley understood, thanks for explaining better than I did. This comes up a lot when you're constructing aggregates.
>
> struct my_aggregate { pin<T> arg1; pin<U> arg2; };
>
> It gets doubly fun when the aggregate is a std::tuple or something like it where you don't /know/ you need in-place constructors.
>
> Basically, perfect forwarding of prvalues is useful and fun but we don't have a way to work with it in the language and that frustrates me.
>

Ok, aggregates make more sense.
You can effectively assemble them inplace from parts from external sources like:

```
my_aggregate {foo_pin(1), foo_pin(3)};
```

that are impossible for constructors as that would require elaborate
nesting of callbacks.

```
struct my_class
{
    pin<T> arg1;
    pin<U> arg2;
    template<typename TT, typename UU>
    my_class(TT&& tt, UU&& uu) : arg1{ tt }, arg2{ uu }
};

template<typename T>
struct delayed
{
   function<T()> f;

   operator T() { return f(); }
};

my_class {foo_pin(1), foo_pin(3)}; //error: can't copy unmovable types!

my_class {delayed{[]{ return foo_pin(1); }}, delayed{[]{ return
foo_pin(2); }} }; // works thanks to delaying callback to member
initialization in constructor
```

> On Tue, Dec 3, 2024 at 3:26 PM Marcin Jaczewski via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> wt., 3 gru 2024 o 15:58 Jonathan Wakely via Std-Proposals
>> <std-proposals_at_[hidden]> napisał(a):
>> >
>> >
>> >
>> > On Tue, 3 Dec 2024 at 14:10, Avi Kivity via Std-Proposals <std-proposals_at_[hidden]> wrote:
>> >>
>> >> We should have a type that pin<> (or senders/receivers) can be
>> >> constructed from, so we can pass them along stuff like std::apply or
>> >> the proposed std::construct.
>> >
>> >
>> > If I understand Gašper's point, the concern is not about constructing a pin<T> (or other immovable type), it's about constructing an object that takes a pin<T> by value as a constructor argument:
>> >
>> > struct MyType {
>> > MyType(pin<int>);
>> > ...
>> > };
>>
>> What is the exact use case of parameters like this?
>> It has a stable address but its temporary. This mean we can't get address it and
>> store it in `MyType` as it will dangle right after the constructor finishes.
>> It can't be mutex as far as I know to have any use of it you need to share it
>> with other code but temporary is very hard to be sent to someone else.
>>
>>
>> >
>> > This wants to be given a pinned int by value, which can work nicely with C++17 guaranteed copy elision. But anything which uses perfect forwarding to pass arguments to the MyType constructor is going to pass it a pin<int>&& which then cannot be moved/copied into the by-value parameter.
>> >
>> > You would need something like:
>> >
>> > auto pin_it = []<typename T>(in_place_type_t<T>, auto&&... a) {
>> > return pin<T>(std::forward<decltype(a)>(a)...);
>> > };
>> >
>> > which returns by value, and then pass that closure to std::construct<MyType>, and have it invoke the closure to get a prvalue that can be passed to the MyType constructor.
>> >
>> > And then we'd want to make that generic and reusable, so you'd be able to compose those prvalue factories:
>> >
>> > auto x = std::construct<MyType>(std::builder<Foo>(args, for, foo), _1, std::builder<Bar>(another, arg), xyz);
>> > MyType m = x("str");
>> >
>> > When invoked, this would do something like:
>> > return MyType(Foo(args, for, foo), "str", Bar(another, arg), xyz);
>> >
>> > i.e. creating prvalues of types Foo and Bar on the fly and passing them directly to the MyType constructor, so there are no references and no forwarding.
>> >
>> > But this gets a lot more complicated than your original idea :-)
>> >
>> >
>> >
>> >
>> >
>> >>
>> >>
>> >> On Tue, 2024-12-03 at 13:10 +0000, Gašper Ažman via Std-Proposals
>> >> wrote:
>> >> > pin<> is an archetype of "nonmovable" - and with sender/receiver and
>> >> > its operation states, "nonmovable" is actually super common.
>> >> >
>> >> > On Tue, Dec 3, 2024 at 11:07 AM Sebastian Wittmeier via Std-Proposals
>> >> > <std-proposals_at_[hidden]> wrote:
>> >> > >
>> >> > >
>> >> > > Hi Avi,
>> >> > >
>> >> > > Is this a contradiction?
>> >> > >
>> >> > > "The problem happen anywhere you use perfect forwarding."
>> >> > > "Just because one class is broken wrt perfect forwarding"
>> >> > >
>> >> > >
>> >> > >
>> >> > > > That's a peculiarity of pin<> and isn't related to construct<>.
>> >> > > >
>> >> > > > The problem with pin<> will happen anywhere you use perfect
>> >> > > > forwarding, for example you can't use it with std::apply(). Just
>> >> > > > because one class is broken wrt perfect forwarding doesn't mean
>> >> > > > we can't use perfect forwarding any more.
>> >>
>> >> --
>> >> Std-Proposals mailing list
>> >> Std-Proposals_at_[hidden]
>> >> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>> >
>> > --
>> > Std-Proposals mailing list
>> > Std-Proposals_at_[hidden]
>> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-12-03 16:34:35