Date: Mon, 27 May 2024 22:48:31 +0200
Hi,
On Mon, May 27, 2024 at 11:43 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
> Then we change it so that it calls "std::return_slot" to get the
> address, and we use "construct_at":
>
> void Func(void)
> {
> mutex *const p = std::construct_at<mutex>( std::return_slot() );
>
There's a way we could make something similar work, I think: instead of void
Func(void), you could have void Func(T* retval) here:
void Func(T* t) /* here, *t is not yet constructed */
{
new(t) T();
doSomethingWithT(t);
}
Then:
> template<typename R, typename... Params>
> consteval auto nrvo( void(*const arg)(Params...) ) -> R(*)(Params...);
>
Instead of this, you'd have:
template<typename R, typename... Params>
consteval auto nrvo( void (*const arg)(R*, Params...) ) -> R(*)(Params...);
Usage is the same. But then, it's very similar to std::factory. In fact, if
we have this:
void Func(T* t, auto const&... args) /* here, *t is not yet constructed */
{
auto pre = doSomethingInAdvance(args...);
new(t) T(pre);
doSomethingWithT(t);
}
, then you can write it in terms of std::factory as:
void Func(auto const& arg, auto const&... args) /* here, *t is not yet
constructed */
{
return std::factory<T>((doSomethingInAdvance(arg, args...), arg),
args..., doSomethingWithT);
}
Starting from std::factory<T>(params..., setup) is a bit more difficult, as
you need a 'before' and 'after' code, and put the 'before' code in the
calculation of any of params... . Now, std::factory<T>(params..., setup)
guarantees that T is constructed (and is constructed in the correct place,
not mistakenly somewhere else); std::nrvo() as above saves you from
rewriting part of your code to continuations style. Ymmw on this - the @
notation fails neither.
Even if you were to opt for std::nrvo, I'd suggest allowing user to return
multiple values, then you'd have something like:
void Func(T* t, U* u, V* v, auto const&... args);
auto Func2 = std::nrvo(Func, std::integral_constant<size_t, 3>);
auto x = Func2(args...); // equivalent to auto [x, unnamed_1, unnamed_2] =
std::nrvo([](std::tuple<T, U, V>* tup, auto const&... args) {
Func(&std::get<0>(tup), &std::get<1>(tup), &std::get<2>(tup), args...); })
, because it essentially comes 'for free' (we either way modify variable
scope schematics) and it solves the getter issue as well. (It does not yet
solve introspection/reflection, but that can be a different thing.)
Thanks,
-lorro
On Mon, May 27, 2024 at 11:43 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
> Then we change it so that it calls "std::return_slot" to get the
> address, and we use "construct_at":
>
> void Func(void)
> {
> mutex *const p = std::construct_at<mutex>( std::return_slot() );
>
There's a way we could make something similar work, I think: instead of void
Func(void), you could have void Func(T* retval) here:
void Func(T* t) /* here, *t is not yet constructed */
{
new(t) T();
doSomethingWithT(t);
}
Then:
> template<typename R, typename... Params>
> consteval auto nrvo( void(*const arg)(Params...) ) -> R(*)(Params...);
>
Instead of this, you'd have:
template<typename R, typename... Params>
consteval auto nrvo( void (*const arg)(R*, Params...) ) -> R(*)(Params...);
Usage is the same. But then, it's very similar to std::factory. In fact, if
we have this:
void Func(T* t, auto const&... args) /* here, *t is not yet constructed */
{
auto pre = doSomethingInAdvance(args...);
new(t) T(pre);
doSomethingWithT(t);
}
, then you can write it in terms of std::factory as:
void Func(auto const& arg, auto const&... args) /* here, *t is not yet
constructed */
{
return std::factory<T>((doSomethingInAdvance(arg, args...), arg),
args..., doSomethingWithT);
}
Starting from std::factory<T>(params..., setup) is a bit more difficult, as
you need a 'before' and 'after' code, and put the 'before' code in the
calculation of any of params... . Now, std::factory<T>(params..., setup)
guarantees that T is constructed (and is constructed in the correct place,
not mistakenly somewhere else); std::nrvo() as above saves you from
rewriting part of your code to continuations style. Ymmw on this - the @
notation fails neither.
Even if you were to opt for std::nrvo, I'd suggest allowing user to return
multiple values, then you'd have something like:
void Func(T* t, U* u, V* v, auto const&... args);
auto Func2 = std::nrvo(Func, std::integral_constant<size_t, 3>);
auto x = Func2(args...); // equivalent to auto [x, unnamed_1, unnamed_2] =
std::nrvo([](std::tuple<T, U, V>* tup, auto const&... args) {
Func(&std::get<0>(tup), &std::get<1>(tup), &std::get<2>(tup), args...); })
, because it essentially comes 'for free' (we either way modify variable
scope schematics) and it solves the getter issue as well. (It does not yet
solve introspection/reflection, but that can be a different thing.)
Thanks,
-lorro
Received on 2024-05-27 20:48:44