Skip to content

Conversation

@AlexGuteniev
Copy link
Contributor

@AlexGuteniev AlexGuteniev commented Nov 12, 2025

Towards #5504. Towards #3803.

Will help sharing the implementation with copyable_function implementation sharing and interaction with function_ref.
Also a minor enhancement on its own.

Steps

Rename to drop _Move_only part

It would be silly to derive copyable_function from _Move_only_function_call.
Ditto for packaged_task from _Move_only_function_base and function from _Move_only_function_call. in vNext.

Avoid saying fields for the data member

This is not directly related to future integrations.
Just prioritizing proper C++ terminology over OOP terminology.
Recognition that OOP is far from being universal, and call wrappers are not necessarily implemented with OOP.

Using void object pointer

⚠️ We may want to revert this part, while keeping the other parts, see details the here ⚠️

This is helpful for function_ref<type>{move_only_function<type>{...}} and function_ref<type>{copyable_function<type>{...}} call unwrapping. Specifically, bound-entity exposition-only member can be of void object pointer type, then the type of _Invoke matches the type of thunk-ptr in function_ref, so we can easily do call unwrapping with thunk elimination.

@frederick-vs-ja has pointed out in #5504 (comment) that the unwrapping involving function_ref is LWG-4264, and the unwrapping with outer function_ref has unexpected effects. I've clarified this on email with Tomasz Kaminski. The idea is that in the case of:

  move_only_function<R(Args...)> f1{...};
  function_ref<R(Args...)> f2{f1};

will not track the changes of f1 value in case of double indirection avoidance, so looks unacceptable, but for this:

  function_ref<R(Args...)> f1{...};
  function_ref<R(Args...) noexcept> f2{f1};

not tracking the changes of f1 may be acceptable, as this imitates a copy of function_ref,

For the reverse unwrapping, that is move_only_function<type>{function_ref<type>{...}} or copyable_function<type>{function_ref<type>{...}}, this change is not enough. I think there are no good options to do the call unwrapping with thunk elimination, will discuss that below. This reverse unwrapping is not problematic semantically though, as the heavy wrappers are supposed to copy/move, and hopefully LWG-4264 will enable it.

Use void object pointer to a non-constant

We have to pass both constant and non-constant objects through the same thunk. For the constant ones the operator() is const. Due to having small functions, we cannot utilize shallow-but-not-deep constant, and have to put const_cast somewhere. This is not a problem for const correctness, as all calls are checked with is_invokable... family, and we don't do anything besides the forwarding and the invoke in the call operator.

Prior to this change, the object was passed as constant, the const_cast was on the thunk side.

The change makes the passed object pointer non-constant, and moves the const_cast to the operator() side.

This makes bound-entity simply void* in case the above part is kept.

Quasi-ABI-break

We can break ABI, but we actually don't do this here if you think of it:

  • Despite the mass renaming, the layout hasn't actually changed
  • There's risk for names to match older or newer names, but I don't think we ever use these names again
  • Not all references are pointers, but reference to a large structure will always be implemented as an object pointer
  • Any object pointers, constant or not, are the same on non-imaginary hardware

Still I want to merge this before ABI changes closure to be extra safe

What's up with unwrapping of inner function_ref

This is about move_only_function<type>{function_ref<type>{...}} or copyable_function<type>{function_ref<type>{...}} unwrapping with thunk elimination.

TL;DR: The win is small and there's no way to make it without penalizing more common use cases.

Whereas the current move_only_function thunks adjust pointer to the beginning of the object internally to find the real callable, the straightforward function_ref implementation would need to pass the direct pointer to a callable, because there's nothing much of function_ref.

The extra thunk not only means extra code, but also extra pointer saved inside move_only_function holding function_ref. Still this looks like the best options.

There are ways to unify move_only_function and function_ref thunk by:

  • Always store direct pointer in move_only_function as well. Will make small move_only_function thunk the same as large, and make small only function self-referencing, that is containing a pointer inside its own data. Will spend extra pointer. Will cause the revert of avoid allocations part from Unwrap call of function passed to move_only_function #5808, as that will not fit even in x64
  • Have the direct pointer computed in move_only_function call. Penalizes the code size and run time of normal move_only_function usage
  • Adjust the pointer in function_ref. Penalizes the code size and run time of normal function_ref usage

Ultimately, the thunk elimination is not very big win, comparing to extra invoke elimination. And we can eliminate extra invoke even without unifying thunks.

@AlexGuteniev AlexGuteniev requested a review from a team as a code owner November 12, 2025 20:58
@github-project-automation github-project-automation bot moved this to Initial Review in STL Code Reviews Nov 12, 2025
@StephanTLavavej StephanTLavavej added the enhancement Something can be improved label Nov 12, 2025
@StephanTLavavej StephanTLavavej self-assigned this Nov 12, 2025
@StephanTLavavej StephanTLavavej added high priority Important! and removed high priority Important! labels Nov 13, 2025
@StephanTLavavej StephanTLavavej removed their assignment Nov 18, 2025
@StephanTLavavej StephanTLavavej moved this from Initial Review to Ready To Merge in STL Code Reviews Nov 18, 2025
@StephanTLavavej StephanTLavavej moved this from Ready To Merge to Merging in STL Code Reviews Nov 19, 2025
@StephanTLavavej
Copy link
Member

I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

@StephanTLavavej StephanTLavavej merged commit a3cc221 into microsoft:main Nov 19, 2025
44 checks passed
@github-project-automation github-project-automation bot moved this from Merging to Done in STL Code Reviews Nov 19, 2025
@StephanTLavavej
Copy link
Member

🏚️ 🏠 🏙️

@AlexGuteniev AlexGuteniev deleted the ramp-up branch November 20, 2025 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Something can be improved

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

2 participants