`<functional>`: Avoid Double Wrapping In `move_only_function` Construction

by ADMIN 75 views

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 empty function.
  • 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 empty function.
  • 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.