C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Copy-construct, move-construct, and PR-construct

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Sun, 3 Sep 2023 14:51:55 -0400
On Sun, Sep 3, 2023 at 11:06 AM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> On Wed, Aug 23, 2023 at 4:10 PM Ville Voutilainen wrote:
> >
> > I wonder what happened to the third strategy, which is to pass as the
> > argument of existing emplace an object
> > that will perform the function invocation in its conversion operator
> > to the optional's element type, which then
> > allows doing this without any library or language changes, and has
> > field experience as a solution to this problem.
>
>
> This works fine so long as the type in question does not have a
> constructor that accepts any type.
> Arthur discusses this limitation here:
>
> https://quuxplusone.github.io/blog/2018/05/17/super-elider-round-2/
>
> I've been thinking though . . . what if we were to have a new overload
> for placement new that accepts 'std::new_in_place' as the argument to
> the constructor

When coming up with solutions, it's often good to lay out the problem
as explicitly as possible.

So, the circumstance we have involves 3 things:

1. A type `T`.
2. An emplace-based API that is going to construct a `T` with an
expression of the form `new(addr) T(std::forward<Args>(args)...)` from
a list of arguments of deduced types via perfect forward.
3. An expression which evaluates to a prvalue of type `T`.

And what we want is to make it so that the result of #3 is used in the
expression in #2 in a way that doesn't provoke a copy/move operation
from #1.

The semi-idiomatic solution is to wrap #3 in a functor which has a
conversion operator to `T` that, when invoked, will result in
evaluating #3. Through the rules of prvalues, no copying or moving
will be invoked.

The issue is that, when looking for user-defined conversions,
conversions in a constructor are given priority over conversion
operators in the given object type. As such, if `T` has a conversion
constructor that is a template which can be used with the wrapper
type, that will break the idiom. The constructor will be preferred
over the conversion operator.

So, your suggestion is to invent a facility that changes this prioritization.

OK, so... why did you shove it into some random standard library type?
That looks like a giant hack that only makes sense for this specific
use case.

A more reasonable idea is to tag either the class as a whole or the
conversion operator with an actual language feature. That feature
would mean that, when the type is used as the source of an implicit
conversion (or the specific operator is possible in such a
conversion), constructors on the destination type are ignored. I'm not
sure if an existing keyword can be used here (`explicit` is absolutely
the wrong one), but there would need to be some property applied to
the type/operator itself. It could even in theory be a contextual
keyword like `final`.

Received on 2023-09-03 18:52:06