std::function
taking an F
is missing a constraintSection: 22.10.17.3.2 [func.wrap.func.con] Status: New Submitter: Ville Voutilainen Opened: 2020-10-31 Last modified: 2021-08-20
Priority: 3
View all other issues in [func.wrap.func.con].
View all issues with New status.
Discussion:
In P0288, any_invocable
is (correctly) constraining
its constructor that takes an F
:
template<class F> any_invocable(F&& f);Let
Constraints:VT
bedecay_t<F>
.
— […]
—
is_constructible_v<VT, F>
istrue
, and— […]
std::function
doesn't do that. According to N4868,
22.10.17.3.2 [func.wrap.func.con] p8 has a constraint for Lvalue-Callable, but not for
copy-constructibility. There is a precondition in p9, but that's not enough for portable
well/ill-formedness.
is_constructible
/constructible_from
queries, we should
add the relevant constraint.
[2020-11-01; Daniel comments]
This issue has some overlap with LWG 2774.
[2021-01-15; Telecon prioritization]
Set priority to 3 following reflector and telecon discussions.
[2021-05-17; Tim comments]
The new constraint causes constraint recursion in an example like:
struct C { explicit C(std::function<void()>); // #1 void operator()() {} }; static_assert(std::is_constructible_v<C, const C&>);
Here, to determine whether a C
can be constructed from a const C
lvalue, the overload resolution will attempt to determine whether the constructor
marked #1
is a viable candidate, which involves a determination of
whether that lvalue can be implicitly converted to a std::function<void()>
,
which, with the new constraint, requires a determination whether
C
is copy-constructible — in other words, whether it can be constructed
from a C
lvalue.
filesystem::path
there, function
here) that is
convertible from every type that are, inter alia, copy constructible,
and this then results in constraint recursion when we ask whether a different
type that is constructible from such a class is copy constructible.
The C
above is reduced from an internal helper type in libstdc++. Given
the ubiquity of call wrappers — types that are callable in their own right
and therefore may not be able to be ruled out by the Lvalue-Callable constraint,
and can also naturally have a constructor that take the wrapped function object
as the argument, triggering the recursion scenario — it is not clear that
there is a good way to add this constraint without causing undue breakage.
[2021-08-20; LWG telecon]
LWG requested that the constraint cited above for
move_only_function
(né any_invocable
)
be moved to a Mandates: element instead, to avoid the same
constraint recursion.
Proposed resolution:
This wording is relative to N4868.
Modify 22.10.17.3.2 [func.wrap.func.con] as indicated:
template<class F> function(F f);-8- Constraints:
-9- Preconditions:F
is Lvalue-Callable (22.10.17.3.1 [func.wrap.func.general]) for argument typesArgTypes...
and return typeR
, andis_copy_constructible_v<F>
istrue
.F
meets the Cpp17CopyConstructible requirements. […]