Date: Mon, 17 Aug 2026 22:56:34 +0800 (CST)
Hi Capita,
Thanks for spending time looking into `Embedded-Function` and for these useful suggestions.
> `F` satisfies the current `is_empty_trivial` test, but constructing an owning wrapper from `f` would normally construct a target object and therefore invoke the copy constructor. Eliminating the object also eliminates that observable effect.
>
> More generally, an empty object does not imply that its identity or lifetime is unobservable; `operator()` may also use `this`. So I suspect that trying to infer semantic statelessness from representation/type traits is difficult to make generally safe.
This is indeed an area where I didn't think things through thoroughly. I used to think `is_empty_trivial` does not indicate stateless only in non-owning semantics (`IsView` == true) and ignored the side effects in the lifetime management in owning semantics.
There are basically two categories of side effects:
1. side effects in lifetime management;
2. use of `this` in `operator()`.
For the first category, adding `std::is_trivially_move_constructible` and `std::is_trivially_copy_constructible` would be sufficient to eliminate the issue. However, there seems to be no reliable way to eliminate the second category. Here is an example:
```cpp
struct F {
uintptr_t operator()() {
return (uintptr_t)this;
}
};
uintptr_t func(ebd::fn<uintptr_t()>& f) {
volatile int u = 42;
auto* volatile d = &u;
(void)d;
return f();
}
int main() {
ebd::fn<uintptr_t()> f = F{};
volatile uintptr_t a = f();
volatile uintptr_t b = func(f);
// A user might reasonably expect `a == b`, but under the current implementation this expectation is violated.
assert(a == b);
}
```
I think it is safe and correct to remove `is_empty_trivial` from `is_stateless`, and only keep `is_statically_callable` and `is_std_op_wrapper`. This aligns well with the direction you mentioned in P1169, P2511, and P3843.
> A smaller observation: I also noticed the recent issue about adding an explicit `Alignment` parameter. I think that is worth doing. For an inplace-only wrapper, capacity and alignment are both part of the storage contract, and applications sometimes deliberately choose stronger alignment than the callable itself requires.
Yes, I agree with you. I'm already refactoring `Embedded-Function` to support an explicit `Alignment` parameter.
Thanks again for the thoughtful review.
Best regards,
Kim J. Smith
At 2026-08-17 16:24:41, "Capita Lai via SG14" <sg14_at_[hidden]> wrote:
Hi Kim,
Thanks for sharing this. I mostly lurk on SG14, so please take this as implementation/design feedback rather than an attempt to speak for the group.
I had a look through the implementation, and I think there is useful implementation experience here beyond simply providing another fixed-storage `std::function`. In particular, I find the separation of the hot invocation path from lifetime management interesting, as well as the explicit treatment of copyable vs. move-only wrappers, signature qualifiers, and empty-call policy. These are all issues that an eventual `inplace_function` design would have to confront.
There is one optimization that I think deserves another look, though: the stateless-functor elimination.
As I understand the current implementation, an owning wrapper treats an `is_empty_trivial` functor as stateless when it is empty, trivially default constructible, and trivially destructible, and then does not store the original object at all.
I don't think those properties are sufficient to establish that the object is semantically stateless. For example:
```cpp
inline int copies = 0;
struct F {
F() = default;
F(const F&) {
++copies;
}
void operator()() const {}
};
static_assert(std::is_empty_v<F>);
static_assert(std::is_trivially_default_constructible_v<F>);
static_assert(std::is_trivially_destructible_v<F>);
F f;
ebd::fn<void()> fn = f;
```
`F` satisfies the current `is_empty_trivial` test, but constructing an owning wrapper from `f` would normally construct a target object and therefore invoke the copy constructor. Eliminating the object also eliminates that observable effect.
More generally, an empty object does not imply that its identity or lifetime is unobservable; `operator()` may also use `this`. So I suspect that trying to infer semantic statelessness from representation/type traits is difficult to make generally safe.
There seems to be some relevant WG21 work pointing in a different direction: represent the absence of runtime callable state explicitly rather than detect it.
* P1169 (`static operator()`):
https://wg21.link/P1169
* P2511 (NTTP callables in type-erased call wrappers):
https://wg21.link/P2511
* P3843 (`std::function_wrapper`):
https://wg21.link/P3843
P3843 in particular explicitly describes a compile-time-known callable wrapper as having no state entities. That seems like a much safer category for this optimization than arbitrary empty functors.
So perhaps one option would be to keep the optimization for cases where statelessness follows directly from the callable representation (static call operator / compile-time-known callable), while storing ordinary empty functor objects normally.
A smaller observation: I also noticed the recent issue about adding an explicit `Alignment` parameter. I think that is worth doing. For an inplace-only wrapper, capacity and alignment are both part of the storage contract, and applications sometimes deliberately choose stronger alignment than the callable itself requires.
Overall, I think Embedded Function is a useful data point for a future `inplace_function` discussion. The full library probably explores a larger design space than a standard `inplace_function` itself would need to expose, but that is also what makes the implementation experience useful: it exposes where the real policy and semantic questions are.
Thanks again for sharing it.
Best regards,
Capita Lai
ycjin_kim via SG14 <sg14_at_lists.isocpp.org> 於 2026年8月15日週六 下午8:32寫道:
Hi SG14,
My name is Kim, a developer interested in embedded systems. I'd like to share a project I've been working on called "Embedded Function" and get the group's feedback.
**Project Introduction**
`Embedded Function` is a lightweight, header-only library that provides a collection of heap-free polymorphic function wrappers (like `ebd::fn`, `ebd::unique_fn`, `ebd::fn_ref`). It's designed for resource-constrained or high-performance environments like game development and embedded systems. The library is freestanding, supports C++11 through C++26, and offers several performance optimizations like branch elimination and zero-stack overhead. It contains only one header file, so it is Godbolt friendly.
**Why I'm sharing this with SG14**
I understand that SG14 has been interested in a non-allocating `inplace_function` for a long time. While the `stdext::inplace_function` implementation exists in the SG14 repository, it seems the standardization effort has not progressed recently. My library aims to be a modern, production-ready alternative. It offers several variants (`fn`, `unique_fn`, `classic_fn`, `fn_ref`) to cover different use cases, similar to what `std::function`, `std::copyable_function`, and `std::function_ref` provide.
I believe `Embedded Function` could serve as a valuable data point or even a potential reference implementation for any future standardization efforts in this area.
**Questions for the group**
- Does the direction of `Embedded Function` align with what SG14 envisions for a standard `inplace_function`?
- Are there any features or design choices you think are missing or could be improved?
- What would be the best way to contribute this work to the ongoing discussion?
The project is open-source on GitHub: https://github.com/Kim-J-Smith/Embedded-Function. I'd be very grateful for any feedback, suggestions, or criticism.
Best regards,
Kim J. Smith
_______________________________________________
SG14 mailing list
SG14_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/sg14
本郵件可能包含威旭資訊股份有限公司之機密或個人資料,僅限指定收件人閱讀與使用。如您並非收件者,請立即刪除本郵件,並勿任意使用、傳播或揭露其內容。收件人應自行確認附件與連結安全,並妥善保護郵件內容,善盡資訊安全責任。
This email may contain confidential or personal information of VICI Holdings, and is intended only for the designated recipient. If you are not the intended recipient, please delete this message immediately and refrain from using, disclosing, or distributing its contents. The recipient is responsible for verifying the safety of attachments and links, and for safeguarding the information in accordance with information security policies.
Thanks for spending time looking into `Embedded-Function` and for these useful suggestions.
> `F` satisfies the current `is_empty_trivial` test, but constructing an owning wrapper from `f` would normally construct a target object and therefore invoke the copy constructor. Eliminating the object also eliminates that observable effect.
>
> More generally, an empty object does not imply that its identity or lifetime is unobservable; `operator()` may also use `this`. So I suspect that trying to infer semantic statelessness from representation/type traits is difficult to make generally safe.
This is indeed an area where I didn't think things through thoroughly. I used to think `is_empty_trivial` does not indicate stateless only in non-owning semantics (`IsView` == true) and ignored the side effects in the lifetime management in owning semantics.
There are basically two categories of side effects:
1. side effects in lifetime management;
2. use of `this` in `operator()`.
For the first category, adding `std::is_trivially_move_constructible` and `std::is_trivially_copy_constructible` would be sufficient to eliminate the issue. However, there seems to be no reliable way to eliminate the second category. Here is an example:
```cpp
struct F {
uintptr_t operator()() {
return (uintptr_t)this;
}
};
uintptr_t func(ebd::fn<uintptr_t()>& f) {
volatile int u = 42;
auto* volatile d = &u;
(void)d;
return f();
}
int main() {
ebd::fn<uintptr_t()> f = F{};
volatile uintptr_t a = f();
volatile uintptr_t b = func(f);
// A user might reasonably expect `a == b`, but under the current implementation this expectation is violated.
assert(a == b);
}
```
I think it is safe and correct to remove `is_empty_trivial` from `is_stateless`, and only keep `is_statically_callable` and `is_std_op_wrapper`. This aligns well with the direction you mentioned in P1169, P2511, and P3843.
> A smaller observation: I also noticed the recent issue about adding an explicit `Alignment` parameter. I think that is worth doing. For an inplace-only wrapper, capacity and alignment are both part of the storage contract, and applications sometimes deliberately choose stronger alignment than the callable itself requires.
Yes, I agree with you. I'm already refactoring `Embedded-Function` to support an explicit `Alignment` parameter.
Thanks again for the thoughtful review.
Best regards,
Kim J. Smith
At 2026-08-17 16:24:41, "Capita Lai via SG14" <sg14_at_[hidden]> wrote:
Hi Kim,
Thanks for sharing this. I mostly lurk on SG14, so please take this as implementation/design feedback rather than an attempt to speak for the group.
I had a look through the implementation, and I think there is useful implementation experience here beyond simply providing another fixed-storage `std::function`. In particular, I find the separation of the hot invocation path from lifetime management interesting, as well as the explicit treatment of copyable vs. move-only wrappers, signature qualifiers, and empty-call policy. These are all issues that an eventual `inplace_function` design would have to confront.
There is one optimization that I think deserves another look, though: the stateless-functor elimination.
As I understand the current implementation, an owning wrapper treats an `is_empty_trivial` functor as stateless when it is empty, trivially default constructible, and trivially destructible, and then does not store the original object at all.
I don't think those properties are sufficient to establish that the object is semantically stateless. For example:
```cpp
inline int copies = 0;
struct F {
F() = default;
F(const F&) {
++copies;
}
void operator()() const {}
};
static_assert(std::is_empty_v<F>);
static_assert(std::is_trivially_default_constructible_v<F>);
static_assert(std::is_trivially_destructible_v<F>);
F f;
ebd::fn<void()> fn = f;
```
`F` satisfies the current `is_empty_trivial` test, but constructing an owning wrapper from `f` would normally construct a target object and therefore invoke the copy constructor. Eliminating the object also eliminates that observable effect.
More generally, an empty object does not imply that its identity or lifetime is unobservable; `operator()` may also use `this`. So I suspect that trying to infer semantic statelessness from representation/type traits is difficult to make generally safe.
There seems to be some relevant WG21 work pointing in a different direction: represent the absence of runtime callable state explicitly rather than detect it.
* P1169 (`static operator()`):
https://wg21.link/P1169
* P2511 (NTTP callables in type-erased call wrappers):
https://wg21.link/P2511
* P3843 (`std::function_wrapper`):
https://wg21.link/P3843
P3843 in particular explicitly describes a compile-time-known callable wrapper as having no state entities. That seems like a much safer category for this optimization than arbitrary empty functors.
So perhaps one option would be to keep the optimization for cases where statelessness follows directly from the callable representation (static call operator / compile-time-known callable), while storing ordinary empty functor objects normally.
A smaller observation: I also noticed the recent issue about adding an explicit `Alignment` parameter. I think that is worth doing. For an inplace-only wrapper, capacity and alignment are both part of the storage contract, and applications sometimes deliberately choose stronger alignment than the callable itself requires.
Overall, I think Embedded Function is a useful data point for a future `inplace_function` discussion. The full library probably explores a larger design space than a standard `inplace_function` itself would need to expose, but that is also what makes the implementation experience useful: it exposes where the real policy and semantic questions are.
Thanks again for sharing it.
Best regards,
Capita Lai
ycjin_kim via SG14 <sg14_at_lists.isocpp.org> 於 2026年8月15日週六 下午8:32寫道:
Hi SG14,
My name is Kim, a developer interested in embedded systems. I'd like to share a project I've been working on called "Embedded Function" and get the group's feedback.
**Project Introduction**
`Embedded Function` is a lightweight, header-only library that provides a collection of heap-free polymorphic function wrappers (like `ebd::fn`, `ebd::unique_fn`, `ebd::fn_ref`). It's designed for resource-constrained or high-performance environments like game development and embedded systems. The library is freestanding, supports C++11 through C++26, and offers several performance optimizations like branch elimination and zero-stack overhead. It contains only one header file, so it is Godbolt friendly.
**Why I'm sharing this with SG14**
I understand that SG14 has been interested in a non-allocating `inplace_function` for a long time. While the `stdext::inplace_function` implementation exists in the SG14 repository, it seems the standardization effort has not progressed recently. My library aims to be a modern, production-ready alternative. It offers several variants (`fn`, `unique_fn`, `classic_fn`, `fn_ref`) to cover different use cases, similar to what `std::function`, `std::copyable_function`, and `std::function_ref` provide.
I believe `Embedded Function` could serve as a valuable data point or even a potential reference implementation for any future standardization efforts in this area.
**Questions for the group**
- Does the direction of `Embedded Function` align with what SG14 envisions for a standard `inplace_function`?
- Are there any features or design choices you think are missing or could be improved?
- What would be the best way to contribute this work to the ongoing discussion?
The project is open-source on GitHub: https://github.com/Kim-J-Smith/Embedded-Function. I'd be very grateful for any feedback, suggestions, or criticism.
Best regards,
Kim J. Smith
_______________________________________________
SG14 mailing list
SG14_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/sg14
本郵件可能包含威旭資訊股份有限公司之機密或個人資料,僅限指定收件人閱讀與使用。如您並非收件者,請立即刪除本郵件,並勿任意使用、傳播或揭露其內容。收件人應自行確認附件與連結安全,並妥善保護郵件內容,善盡資訊安全責任。
This email may contain confidential or personal information of VICI Holdings, and is intended only for the designated recipient. If you are not the intended recipient, please delete this message immediately and refrain from using, disclosing, or distributing its contents. The recipient is responsible for verifying the safety of attachments and links, and for safeguarding the information in accordance with information security policies.
Received on 2026-08-17 14:56:45
