Date: Mon, 2 Dec 2024 11:49:00 +0000
`pin` is a common but not-standardized wrapper that forbids moving or
copying. It's the common way of saying "the address of this object is
stable and it won't move".
To a first approximation, `pin` looks like this (I'm omitting all the
common tricks to get direct initialization to work etc):
```
template <typename T>
struct pin {
T value;
pin(pin&&) = delete;
pin(pin const&) = delete;
auto operator=(pin&&) = delete;
auto operator=(pin const&) = delete;
};
```
And yes, all wrappers have this problem, but other than `emplace` and
`apply`, they store the values in between so there's nothing to be done
about that. Effectively the problem is correctly forwarding pr-values.
You can get around it by having a helper such as
```
template <typename... Ts>
struct emplace {
std::tuple<Ts...> args;
template <typename T>
auto operator T() && {
return T{std::get<i>(std::move(args))...}; // expand on Ts, you
need a lambda but I'm too lazy to write it
}
};
```
It's also not the full helper, there's a paper and I forget what it's
called, but that's the best we can do with perfect-forwarding right now and
it's sad.
On Mon, Dec 2, 2024 at 11:02 AM Avi Kivity <avi_at_[hidden]> wrote:
> What's pin<int>?
>
> Don't all helpers that rely on perfect forwarding suffer from this? e.g.
> std::bind(), std::bind_front(), emplace()?
>
> Shouldn't we rename "perfect forwarding" to "imperfect forwarding" if it
> isn't able to perfectly forward some types?
>
> On Sun, 2024-12-01 at 19:31 +0000, Gašper Ažman via Std-Proposals wrote:
>
> The only reason to standardize this would be if somehow this function was
> magically blessed to perfectly forward constructor arguments to the
> constructor, including non-movable pr-values:
>
> MyType(pin<int>)
>
> is not constructible using std:construct without special language support.
>
> On Sun, Dec 1, 2024 at 7:28 PM Andrey Semashev via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> On December 1, 2024 9:43:24 PM Avi Kivity <avi_at_[hidden]> wrote:
>
> > On Sun, 2024-12-01 at 21:25 +0300, Andrey Semashev wrote:
> >> On December 1, 2024 7:57:45 PM Avi Kivity <avi_at_[hidden]> wrote:
> >>
> >>> On Sun, 2024-12-01 at 19:11 +0300, Andrey Semashev via Std-
> >>> Proposals
> >>> wrote:
> >>
> >>> Or we can make it a
> >>> niebloid.
> >>
> >> Sorry, I don't know what this means.
> >
> >
> > A technique used in std::ranges to avoid such pointers-to-functions.
> >
> > template <typename T>
> > struct _Impl_construct
> > template <typename... Args>
> > static T operator()(Args... args) { return
> > T(std::forward<Args>(args)...); }
> > };
> >
> > template <typename T>
> > inline _Impl_construct construct;
>
> This would make taking address of std::construct not work, which is
> unexpected.
>
> std::ranges::transform(&std::construct<T>)
>
>
>
>
>
>
copying. It's the common way of saying "the address of this object is
stable and it won't move".
To a first approximation, `pin` looks like this (I'm omitting all the
common tricks to get direct initialization to work etc):
```
template <typename T>
struct pin {
T value;
pin(pin&&) = delete;
pin(pin const&) = delete;
auto operator=(pin&&) = delete;
auto operator=(pin const&) = delete;
};
```
And yes, all wrappers have this problem, but other than `emplace` and
`apply`, they store the values in between so there's nothing to be done
about that. Effectively the problem is correctly forwarding pr-values.
You can get around it by having a helper such as
```
template <typename... Ts>
struct emplace {
std::tuple<Ts...> args;
template <typename T>
auto operator T() && {
return T{std::get<i>(std::move(args))...}; // expand on Ts, you
need a lambda but I'm too lazy to write it
}
};
```
It's also not the full helper, there's a paper and I forget what it's
called, but that's the best we can do with perfect-forwarding right now and
it's sad.
On Mon, Dec 2, 2024 at 11:02 AM Avi Kivity <avi_at_[hidden]> wrote:
> What's pin<int>?
>
> Don't all helpers that rely on perfect forwarding suffer from this? e.g.
> std::bind(), std::bind_front(), emplace()?
>
> Shouldn't we rename "perfect forwarding" to "imperfect forwarding" if it
> isn't able to perfectly forward some types?
>
> On Sun, 2024-12-01 at 19:31 +0000, Gašper Ažman via Std-Proposals wrote:
>
> The only reason to standardize this would be if somehow this function was
> magically blessed to perfectly forward constructor arguments to the
> constructor, including non-movable pr-values:
>
> MyType(pin<int>)
>
> is not constructible using std:construct without special language support.
>
> On Sun, Dec 1, 2024 at 7:28 PM Andrey Semashev via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> On December 1, 2024 9:43:24 PM Avi Kivity <avi_at_[hidden]> wrote:
>
> > On Sun, 2024-12-01 at 21:25 +0300, Andrey Semashev wrote:
> >> On December 1, 2024 7:57:45 PM Avi Kivity <avi_at_[hidden]> wrote:
> >>
> >>> On Sun, 2024-12-01 at 19:11 +0300, Andrey Semashev via Std-
> >>> Proposals
> >>> wrote:
> >>
> >>> Or we can make it a
> >>> niebloid.
> >>
> >> Sorry, I don't know what this means.
> >
> >
> > A technique used in std::ranges to avoid such pointers-to-functions.
> >
> > template <typename T>
> > struct _Impl_construct
> > template <typename... Args>
> > static T operator()(Args... args) { return
> > T(std::forward<Args>(args)...); }
> > };
> >
> > template <typename T>
> > inline _Impl_construct construct;
>
> This would make taking address of std::construct not work, which is
> unexpected.
>
> std::ranges::transform(&std::construct<T>)
>
>
>
>
>
>
Received on 2024-12-02 11:49:13