Date: Sun, 06 Jul 2025 23:24:35 +0300
I wrote it up:
https://github.com/avikivity/cpp-std-proposals/blob/std-construct/std-construct.md#proposal-for-stdconstruct-function-object
On Wed, 2025-05-14 at 22:30 +0300, Avi Kivity wrote:
> You're correct, std::construct should be a variable template with one
> parameter.
>
> Regarding make_obj vs std::construct, obj is not a word, and I think
> the standard should try hard to use words. I think std::construct is
> consistent with std::construct_at.
>
> btw are make_obj_using_allocator and std::construct related? The
> former allocates, the latter does not.
>
> On Sun, 2025-05-11 at 12:38 -0400, Arthur O'Dwyer wrote:
> > Hi Avi,
> >
> > FWIW, I'm not sure P3312 is going anywhere; notice it's still in
> > EWGI, and the syntax/semantics proposed don't seem very C++-ish to
> > me.
> > OTOH, your `std::construct` as written is very similar to the
> > existing `std::make_obj_using_allocator [1]`; the only difference
> > is that make_obj_using_allocator takes a first argument of type
> > std::allocator<T>, whereas yours omits that parameter.
> > OTOOH, your `std::construct` definitely doesn't achieve your
> > purpose as written. You wrote a template of 1+K parameters, and
> > then instantiated it with 1+0 arguments:
> > https://godbolt.org/z/8dnqThW1Y
> >
> > template<class T, class... Args>
> > T std_construct(Args&&... args) {
> > return T(std::forward<Args>(args)...);
> > }
> >
> > struct Arg1 {} arg1;
> > struct Arg2 {} arg2;
> > struct Arg3 {} arg3;
> > struct Type1 {
> > explicit Type1(Arg1, Arg2&, Arg3);
> > };
> >
> > This code allows you to write:
> >
> > Type1 (*pf3)(Arg1&&, Arg2&, Arg3&&) = std_construct<Type1, Arg1,
> > Arg2&, Arg3>;
> >
> > But it certainly does not allow you to write either:
> >
> > Type1 (*pf0)() = std_construct<Type1>; // no, Type1 has no zero-
> > argument constructor
> > Type1 (*pf3)(Arg1, Arg2&, Arg3) = std_construct<Type1>; // no,
> > Typ1 has no zero-argument constructor and pf3 doesn't have the same
> > function type as the zero-argument std_construct<Type1>
> > auto make_something = std::bind_front(std_construct<Type1>, ~~~);
> > // certainly not
> >
> > What you need for a generic-lambda-style thing is for
> > std::construct<T> to be a callable object in its own right, like
> > this:
> > https://godbolt.org/z/TTbf6cGdx
> >
> > All Ranges adaptors are "partially applied templates" similar to
> > what we're doing here.
> > Should make_obj_using_allocator be a "partially applicable"
> > template like this, instead of a "fully applicable only" template
> > as it currently is?
> >
> > Should there be a new "partially applicable" template named
> > std::make_obj and/or std::construct? (I would prefer the former
> > name, FWIW, for consistency.)
> >
> > Should there be a new core-language feature that permits automatic
> > handling of the "partial application" of templates, somehow?
> > (But this last would run into trouble with backward compatibility,
> > because your `std::construct<Type1>` from above is already legal
> > C++ today: it just unambiguously does something different from what
> > you want it to do. Making it automatically represent a "partial but
> > not complete specification" of std::construct's template parameter
> > list would change its meaning, possibly changing the meaning of
> > existing code.)
> >
> > my $.02,
> > –Arthur
> >
> >
> > On Sun, May 11, 2025 at 7:37 AM Avi Kivity via Std-Proposals
> > <std-proposals_at_[hidden]> wrote:
> > > This is superceded by P3312 [1].
> > > Instead of std::construct<T>(...), write (&T::T)(...).
> > > [1]
> > >
> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf
> > >
> > > On Sun, 2024-12-01 at 17:57 +0200, Avi Kivity wrote:
> > > > Functions and member functions are invocable, but constructors
> > > > are not.
> > > >
> > > > I propose to add
> > > >
> > > > template <typename T, typename... Args>
> > > > T std::construct(Args&&... args) {
> > > > return T(std::forward<decltype(Args)>(args)...);
> > > > }
> > > >
> > > > With this, we can pass a constructor where other functions can
> > > > be
> > > > passed.
> > > >
> > > > // build a callback that creates and returns a Type1 thing
> > > > std::function<Type1 (Arg3)> make_somthing =
> > > > std::bind_front(std::construct<Type1>, arg1, std::ref(arg2));
> > > >
> > > > // transform a vector of ints to a vector of some other
> > > > type
> > > > auto foo = some_container |
> > > > std::views::transform(std::construct<AnotherType>) |
> > > > std::ranges::to<std::vector>();
>
[1] std::make_obj_using_allocator
https://en.cppreference.com/w/cpp/memory/make_obj_using_allocator
https://github.com/avikivity/cpp-std-proposals/blob/std-construct/std-construct.md#proposal-for-stdconstruct-function-object
On Wed, 2025-05-14 at 22:30 +0300, Avi Kivity wrote:
> You're correct, std::construct should be a variable template with one
> parameter.
>
> Regarding make_obj vs std::construct, obj is not a word, and I think
> the standard should try hard to use words. I think std::construct is
> consistent with std::construct_at.
>
> btw are make_obj_using_allocator and std::construct related? The
> former allocates, the latter does not.
>
> On Sun, 2025-05-11 at 12:38 -0400, Arthur O'Dwyer wrote:
> > Hi Avi,
> >
> > FWIW, I'm not sure P3312 is going anywhere; notice it's still in
> > EWGI, and the syntax/semantics proposed don't seem very C++-ish to
> > me.
> > OTOH, your `std::construct` as written is very similar to the
> > existing `std::make_obj_using_allocator [1]`; the only difference
> > is that make_obj_using_allocator takes a first argument of type
> > std::allocator<T>, whereas yours omits that parameter.
> > OTOOH, your `std::construct` definitely doesn't achieve your
> > purpose as written. You wrote a template of 1+K parameters, and
> > then instantiated it with 1+0 arguments:
> > https://godbolt.org/z/8dnqThW1Y
> >
> > template<class T, class... Args>
> > T std_construct(Args&&... args) {
> > return T(std::forward<Args>(args)...);
> > }
> >
> > struct Arg1 {} arg1;
> > struct Arg2 {} arg2;
> > struct Arg3 {} arg3;
> > struct Type1 {
> > explicit Type1(Arg1, Arg2&, Arg3);
> > };
> >
> > This code allows you to write:
> >
> > Type1 (*pf3)(Arg1&&, Arg2&, Arg3&&) = std_construct<Type1, Arg1,
> > Arg2&, Arg3>;
> >
> > But it certainly does not allow you to write either:
> >
> > Type1 (*pf0)() = std_construct<Type1>; // no, Type1 has no zero-
> > argument constructor
> > Type1 (*pf3)(Arg1, Arg2&, Arg3) = std_construct<Type1>; // no,
> > Typ1 has no zero-argument constructor and pf3 doesn't have the same
> > function type as the zero-argument std_construct<Type1>
> > auto make_something = std::bind_front(std_construct<Type1>, ~~~);
> > // certainly not
> >
> > What you need for a generic-lambda-style thing is for
> > std::construct<T> to be a callable object in its own right, like
> > this:
> > https://godbolt.org/z/TTbf6cGdx
> >
> > All Ranges adaptors are "partially applied templates" similar to
> > what we're doing here.
> > Should make_obj_using_allocator be a "partially applicable"
> > template like this, instead of a "fully applicable only" template
> > as it currently is?
> >
> > Should there be a new "partially applicable" template named
> > std::make_obj and/or std::construct? (I would prefer the former
> > name, FWIW, for consistency.)
> >
> > Should there be a new core-language feature that permits automatic
> > handling of the "partial application" of templates, somehow?
> > (But this last would run into trouble with backward compatibility,
> > because your `std::construct<Type1>` from above is already legal
> > C++ today: it just unambiguously does something different from what
> > you want it to do. Making it automatically represent a "partial but
> > not complete specification" of std::construct's template parameter
> > list would change its meaning, possibly changing the meaning of
> > existing code.)
> >
> > my $.02,
> > –Arthur
> >
> >
> > On Sun, May 11, 2025 at 7:37 AM Avi Kivity via Std-Proposals
> > <std-proposals_at_[hidden]> wrote:
> > > This is superceded by P3312 [1].
> > > Instead of std::construct<T>(...), write (&T::T)(...).
> > > [1]
> > >
> > https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf
> > >
> > > On Sun, 2024-12-01 at 17:57 +0200, Avi Kivity wrote:
> > > > Functions and member functions are invocable, but constructors
> > > > are not.
> > > >
> > > > I propose to add
> > > >
> > > > template <typename T, typename... Args>
> > > > T std::construct(Args&&... args) {
> > > > return T(std::forward<decltype(Args)>(args)...);
> > > > }
> > > >
> > > > With this, we can pass a constructor where other functions can
> > > > be
> > > > passed.
> > > >
> > > > // build a callback that creates and returns a Type1 thing
> > > > std::function<Type1 (Arg3)> make_somthing =
> > > > std::bind_front(std::construct<Type1>, arg1, std::ref(arg2));
> > > >
> > > > // transform a vector of ints to a vector of some other
> > > > type
> > > > auto foo = some_container |
> > > > std::views::transform(std::construct<AnotherType>) |
> > > > std::ranges::to<std::vector>();
>
[1] std::make_obj_using_allocator
https://en.cppreference.com/w/cpp/memory/make_obj_using_allocator
Received on 2025-07-06 20:24:42