Date: Tue, 19 Nov 2024 06:43:59 +0100
Try to implement that before proposing it, as you would essentially have to
implement all versions of the func at once and then disable everything that
should not be enabled. Tricky to get completely right.
// Robin
On Mon, Nov 18, 2024, 22:41 Marcin Jaczewski via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> pon., 18 lis 2024 o 17:02 Arthur O'Dwyer via Std-Proposals
> <std-proposals_at_[hidden]> napisał(a):
> >
> > On Mon, Nov 18, 2024 at 10:23 AM Robin Savonen Söderholm via
> Std-Proposals <std-proposals_at_[hidden]> wrote:
> >>
> >> Hi!
> >>
> >> In certain embedded situations, you may want to avoid needless heap
> allocations. Since the major compiler makers apply "small object
> optimisation", it would be nice to somehow query if a type satisfies the
> SOO or if std::function would do a heap allocation (something that we could
> maybe static_assert in the very least if no other options are automatically
> available).
> >> I believe that whether an object satisfies SOO or not may depend on
> both size and alignment of the type, so the most straight-forward API I can
> think of is something along the lines of
> `std::function_is_inplace_v<FUNCTION, TYPE>` or something like that.
> >
> >
> > It can also depend on the trivial copyability (or trivial
> relocatability) of the type, the nothrow move-constructibility, etc. etc.,
> depending on the vendor.
> > Nit: When we say "the type," we mean "the decayed type," e.g. if TYPE is
> a function type, we really care about the function pointer type, not the
> function type.
> >
> > using F = std::function<int(int)>;
> >
> > The trait you're looking for would have to be a member of `F`, not some
> sort of global trait unrelated to `F`.
> > It feels to me like there are several possible designs (type trait?
> constexpr function? member function of a constructed `F`?) but the simplest
> is a type trait:
> >
> > template<class T>
> > F wrap_in_function(T&& t) {
> > static_assert(F::uses_inplace_storage<T>::value);
> > return F(std::forward<T>(t));
> > }
> >
> > I think the biggest objections to such a function are minor but
> easy-to-stall-a-WG21-proposal:
> > (1) Naming is hard. It's easier now that we have the adjective "inplace"
> (as in "inplace_vector"), but notice the vast difference between your
> suggested name and mine. Should the standard library types provide both
> `F::bikeshed<T>::value` and `F::bikeshed_v<T>`? What about user-provided
> `F`s — do they need to provide both names?
> > (2) By exposing this information to the programmer, you're basically
> baking it into the ABI more than it used to be. A lot of type-erasure
> schemes continue to work at the ABI level even if the internal
> small-storage criterion changes over time; but if you actually expose the
> criterion to the user, then the user might start making ABI/API-relevant
> decisions based on that criterion, and then the vendor can't change their
> criterion without breaking the user's code. Of course this is already the
> case if the user is implicitly relying on the vendor's criterion in order
> to achieve correctness at runtime (e.g. assuming that a certain
> construction won't heap-allocate and therefore won't block), but WG21 has a
> lot more tolerance for breaking runtime behavior than breaking actual
> compilation. (A form of the quantitative fallacy: it's a lot easier to
> measure "broken builds" than "subtly broken runtime behavior" and so the
> former gets a lot more attention than the latter.)
> >
> >>
> >> It would also be nice to have a "std::inplace_function" that is a
> stand-in replacement for std::function when it is unfit for similar
> reasons. I see a "SG14" inplace_function, but I am unsure if
> inplace_function has been up for discussion before and shot down for some
> reason.
> >
> >
> > I don't think it's ever been up for discussion. Carl Cook started work
> on a proposal D0419 in 2016, but never completed it and it was never put
> into a mailing.
> > The current version of sg14::inplace_function is here:
> >
> https://github.com/Quuxplusone/SG14/?tab=readme-ov-file#in-place-type-erased-types-future--c14
> >
> > IMHO inplace_function shouldn't be standardized (and neither should
> std::move_only_function or std::copyable_function have been standardized)
> because there are simply too many knobs to fiddle with, and the correct
> knob-settings are known only to the programmer of each individual codebase.
> It is a fool's errand to try to standardize each possible setting of the
> knobs, each under a different name. (immovable_function, nonnull_function,
> non_implicitly_void_converting_function, etc. etc.) And we know this not
> just intuitively but also empirically: the STL already picked the "wrong"
> choice in several of these dimensions, several times in a row.
> >
> https://quuxplusone.github.io/blog/2019/03/27/design-space-for-std-function/
>
> What if we make all these configs exposed as one parameter type?
> Image template:
>
> ```
> template<typename Func, typename Config = func_def>
> class base_func;
>
> base_func<int(), func_non_move> foo1;
> base_func<int(), sbo<16, 8>> foo2;
> base_func<int(), custom<sbo<16, 8>, func_move, func_copy>> foo3;
> base_func<int(), my_own_tag<10>> foo4;
> ```
>
> And function implementation will querry some data from this config, we
> could define too who conversion
> work between diffrent types.
> If the committee forgets some "dimension" it can add new tags later
> that expose this to users.
> Could this work better?
>
>
>
>
> >
> > Data point: AFAICT, boost::function does not support anything like
> `F::uses_inplace_storage<T>`.
> >
> > HTH,
> > Arthur
> > --
> > 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
>
implement all versions of the func at once and then disable everything that
should not be enabled. Tricky to get completely right.
// Robin
On Mon, Nov 18, 2024, 22:41 Marcin Jaczewski via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> pon., 18 lis 2024 o 17:02 Arthur O'Dwyer via Std-Proposals
> <std-proposals_at_[hidden]> napisał(a):
> >
> > On Mon, Nov 18, 2024 at 10:23 AM Robin Savonen Söderholm via
> Std-Proposals <std-proposals_at_[hidden]> wrote:
> >>
> >> Hi!
> >>
> >> In certain embedded situations, you may want to avoid needless heap
> allocations. Since the major compiler makers apply "small object
> optimisation", it would be nice to somehow query if a type satisfies the
> SOO or if std::function would do a heap allocation (something that we could
> maybe static_assert in the very least if no other options are automatically
> available).
> >> I believe that whether an object satisfies SOO or not may depend on
> both size and alignment of the type, so the most straight-forward API I can
> think of is something along the lines of
> `std::function_is_inplace_v<FUNCTION, TYPE>` or something like that.
> >
> >
> > It can also depend on the trivial copyability (or trivial
> relocatability) of the type, the nothrow move-constructibility, etc. etc.,
> depending on the vendor.
> > Nit: When we say "the type," we mean "the decayed type," e.g. if TYPE is
> a function type, we really care about the function pointer type, not the
> function type.
> >
> > using F = std::function<int(int)>;
> >
> > The trait you're looking for would have to be a member of `F`, not some
> sort of global trait unrelated to `F`.
> > It feels to me like there are several possible designs (type trait?
> constexpr function? member function of a constructed `F`?) but the simplest
> is a type trait:
> >
> > template<class T>
> > F wrap_in_function(T&& t) {
> > static_assert(F::uses_inplace_storage<T>::value);
> > return F(std::forward<T>(t));
> > }
> >
> > I think the biggest objections to such a function are minor but
> easy-to-stall-a-WG21-proposal:
> > (1) Naming is hard. It's easier now that we have the adjective "inplace"
> (as in "inplace_vector"), but notice the vast difference between your
> suggested name and mine. Should the standard library types provide both
> `F::bikeshed<T>::value` and `F::bikeshed_v<T>`? What about user-provided
> `F`s — do they need to provide both names?
> > (2) By exposing this information to the programmer, you're basically
> baking it into the ABI more than it used to be. A lot of type-erasure
> schemes continue to work at the ABI level even if the internal
> small-storage criterion changes over time; but if you actually expose the
> criterion to the user, then the user might start making ABI/API-relevant
> decisions based on that criterion, and then the vendor can't change their
> criterion without breaking the user's code. Of course this is already the
> case if the user is implicitly relying on the vendor's criterion in order
> to achieve correctness at runtime (e.g. assuming that a certain
> construction won't heap-allocate and therefore won't block), but WG21 has a
> lot more tolerance for breaking runtime behavior than breaking actual
> compilation. (A form of the quantitative fallacy: it's a lot easier to
> measure "broken builds" than "subtly broken runtime behavior" and so the
> former gets a lot more attention than the latter.)
> >
> >>
> >> It would also be nice to have a "std::inplace_function" that is a
> stand-in replacement for std::function when it is unfit for similar
> reasons. I see a "SG14" inplace_function, but I am unsure if
> inplace_function has been up for discussion before and shot down for some
> reason.
> >
> >
> > I don't think it's ever been up for discussion. Carl Cook started work
> on a proposal D0419 in 2016, but never completed it and it was never put
> into a mailing.
> > The current version of sg14::inplace_function is here:
> >
> https://github.com/Quuxplusone/SG14/?tab=readme-ov-file#in-place-type-erased-types-future--c14
> >
> > IMHO inplace_function shouldn't be standardized (and neither should
> std::move_only_function or std::copyable_function have been standardized)
> because there are simply too many knobs to fiddle with, and the correct
> knob-settings are known only to the programmer of each individual codebase.
> It is a fool's errand to try to standardize each possible setting of the
> knobs, each under a different name. (immovable_function, nonnull_function,
> non_implicitly_void_converting_function, etc. etc.) And we know this not
> just intuitively but also empirically: the STL already picked the "wrong"
> choice in several of these dimensions, several times in a row.
> >
> https://quuxplusone.github.io/blog/2019/03/27/design-space-for-std-function/
>
> What if we make all these configs exposed as one parameter type?
> Image template:
>
> ```
> template<typename Func, typename Config = func_def>
> class base_func;
>
> base_func<int(), func_non_move> foo1;
> base_func<int(), sbo<16, 8>> foo2;
> base_func<int(), custom<sbo<16, 8>, func_move, func_copy>> foo3;
> base_func<int(), my_own_tag<10>> foo4;
> ```
>
> And function implementation will querry some data from this config, we
> could define too who conversion
> work between diffrent types.
> If the committee forgets some "dimension" it can add new tags later
> that expose this to users.
> Could this work better?
>
>
>
>
> >
> > Data point: AFAICT, boost::function does not support anything like
> `F::uses_inplace_storage<T>`.
> >
> > HTH,
> > Arthur
> > --
> > 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-11-19 05:44:16