`<functional>`: Avoid Double Wrapping In `move_only_function` Construction
Introduction
In the context of C++ programming, the construction of polymorphic function wrappers is a crucial aspect of functional programming. However, the process of wrapping and unwrapping these functions can lead to double wrapping, which can have unintended consequences. In this article, we will delve into the concept of double wrapping and explore the implications of avoiding it in the construction of move_only_function
.
Understanding Double Wrapping
Double wrapping occurs when a polymorphic function wrapper is constructed from another wrapper, resulting in an additional layer of wrapping. This can lead to issues such as increased memory usage, slower performance, and unexpected behavior. The C++ standard committee has acknowledged the importance of avoiding double wrapping and has provided guidance on how to achieve this.
WG21-P2548R2 and the Relaxation of Requirements
WG21-P2548R2 is a proposal that has relaxed some requirements for polymorphic function wrappers. Specifically, it has added wording to [func.wrap.general] that allows for the construction of wrappers from one another without double wrapping. However, this relaxation does not apply to the construction of function
, even in the upcoming C++23 standard.
The Case of move_only_function
move_only_function
is a type of polymorphic function wrapper that is designed to be move-only. Unlike function
, which can be copied, move_only_function
is intended to be moved from one object to another. This makes it possible to unwrap the target object in the construction of move_only_function
, avoiding double wrapping.
Personal Concerns and Recommendations
When constructing a move_only_function
from an empty function
, it is essential to maintain the throwing-on-invocation behavior. This means that the constructed move_only_function
cannot be empty. Additionally, it may be beneficial to recognize program-defined specializations and avoid invalid unwrapping for them. However, given the current state of support for program-defined specializations of function
, it may be plausible to ignore this aspect.
Treating the Allowance as a DR
Given the importance of avoiding double wrapping in move_only_function
construction, it is recommended to treat the allowance as a Defect Report (DR) against C++23. This would ensure that the implementation is ABI-critical and can be relied upon by libstdc++ and other libraries.
Example Code
Here is an example of constructing a move_only_function
from an empty function
:
move_only_function<void(T)>
f{function<void(T)>{[](T) {}}};
T t;
f(t); // it is unspecified how many copies of T are made
In this example, the move_only_function
f
is constructed from an empty function
. The target
member function of f
is not observable, allowing for the unwrapping of the target object.
Conclusion
Avoiding double wrapping in move_only_function
construction is crucial for maintaining the integrity of polymorphic function wrappers. By recognizing the allowance as a DR against C++23 and implementing it un, we can ensure that the construction of move_only_function
is ABI-critical and reliable. Additionally, maintaining the throwing-on-invocation behavior and recognizing program-defined specializations can help to avoid invalid unwrapping and ensure the correctness of the implementation.
Recommendations
- Treat the allowance as a DR against C++23.
- Implement the allowance unconditionally for
move_only_function
. - Maintain the throwing-on-invocation behavior when constructing a
move_only_function
from an emptyfunction
. - Recognize program-defined specializations and avoid invalid unwrapping for them.
Q: What is double wrapping in move_only_function
construction?
A: Double wrapping occurs when a polymorphic function wrapper is constructed from another wrapper, resulting in an additional layer of wrapping. This can lead to issues such as increased memory usage, slower performance, and unexpected behavior.
Q: Why is avoiding double wrapping important?
A: Avoiding double wrapping is crucial for maintaining the integrity of polymorphic function wrappers. It ensures that the construction of move_only_function
is reliable, efficient, and correct.
Q: What is the current state of support for program-defined specializations of function
?
A: The current state of support for program-defined specializations of function
is broken. This means that program-defined specializations may not work as expected, and it may be beneficial to ignore this aspect when implementing the allowance.
Q: What is the recommended approach for treating the allowance as a DR against C++23?
A: The recommended approach is to treat the allowance as a Defect Report (DR) against C++23. This would ensure that the implementation is ABI-critical and can be relied upon by libstdc++ and other libraries.
Q: How can I maintain the throwing-on-invocation behavior when constructing a move_only_function
from an empty function
?
A: To maintain the throwing-on-invocation behavior, you can ensure that the constructed move_only_function
is not empty. This can be achieved by checking the target object of the move_only_function
before invoking it.
Q: What are the implications of recognizing program-defined specializations and avoiding invalid unwrapping for them?
A: Recognizing program-defined specializations and avoiding invalid unwrapping for them can help to ensure the correctness of the implementation. However, given the current state of support for program-defined specializations of function
, it may be plausible to ignore this aspect.
Q: What is the recommended approach for implementing the allowance unconditionally for move_only_function
?
A: The recommended approach is to implement the allowance unconditionally for move_only_function
. This would ensure that the construction of move_only_function
is reliable, efficient, and correct.
Q: What are the benefits of avoiding double wrapping in move_only_function
construction?
A: The benefits of avoiding double wrapping in move_only_function
construction include:
- Increased reliability: Avoiding double wrapping ensures that the construction of
move_only_function
is reliable and efficient. - Improved performance: Avoiding double wrapping can lead to improved performance by reducing the overhead of wrapping and unwrapping.
- Correctness: Avoiding double wrapping ensures that the implementation is correct and free from unexpected behavior.
Q: What are the next steps for implementing the allowance?
A: The next steps for implementing the allowance include:
- Treating the allowance as a DR against C++23.
- Implementing the allowance unconditionally for
move_only_function
. - Maintaining the throwing-invocation behavior when constructing a
move_only_function
from an emptyfunction
. - Recognizing program-defined specializations and avoiding invalid unwrapping for them.
By following these steps, you can ensure that the construction of move_only_function
is reliable, efficient, and correct.