<functional>: Avoid double wrapping in move_only_function construction (original) (raw)
WG21-P2548R6 relaxed some requirements for polymorphic function wrappers by adding wording in [func.wrap.general].
- Let
tbe an object of a type that is a specialization offunction,copyable_function, ormove_only_function, such that the target objectxofthas a type that is a specialization offunction,copyable_function, ormove_only_function. Each argument of the invocation ofxevaluated as part of the invocation oftmay alias an argument in the same position in the invocation oftthat has the same type, even if the corresponding parameter is not of reference type.[Example 1:
move_only_function<void(T)> f{copyable_function<void(T)>{ {}}}; T t; f(t); // it is unspecified how many copies of T are made
— _end example_]
- Recommended practice: Implementations should avoid double wrapping when constructing polymorphic wrappers from one another.
However, if I understand correctly, we can't avoid double wrapping in construction of function, even in vNext, because it's target object is observable via the target member function.
For move_only_function and copyable_function, it seems possible to unwrap in construction, because the target object is not observable and thus can be non-existent under some conditions.
I think its better to treat the allowance as a DR against C++23 (i.e. to implement it for move_only_function unconditionally), because that is ABI-critical and libstdc++ starts doing so recently.
Personal concerns:
- When constructing a
move_only_functionfrom an emptyfunction, we need to keep the throwing-on-invocation behavior, which means that the constructedmove_only_functioncan't be empty. - It might be better to recognize program-defined specializations and avoid invalid unwrapping for them. But since support for program-defined specializations of
functionis already broken, and the program-defined specializations can hardly be helpful, it might be also plausible not to do this.