Skip to content

<functional>: Avoid double wrapping in move_only_function construction #5504

@frederick-vs-ja

Description

@frederick-vs-ja

WG21-P2548R6 relaxed some requirements for polymorphic function wrappers by adding wording in [func.wrap.general].

  1. Let t be an object of a type that is a specialization of function, copyable_function, or move_only_function, such that the target object x of t has a type that is a specialization of function, copyable_function, or move_only_function. Each argument of the invocation of x evaluated as part of the invocation of t may alias an argument in the same position in the invocation of t that 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 t;
f(t);                               // it is unspecified how many copies of T are made

end example]

  1. 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_function from an empty function, we need to keep the throwing-on-invocation behavior, which means that the constructed move_only_function can'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 function is already broken, and the program-defined specializations can hardly be helpful, it might be also plausible not to do this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions