Motivation
Several internal call paths use direct function-call syntax:
Direct invocation supports ordinary functions and function objects, but not the full standard INVOKE model. std::invoke uniformly supports:
- function objects and lambdas;
- function pointers;
- pointers to member functions;
- pointers to member data;
std::reference_wrapper targets.
Using it would make deferred callable interfaces align with standard C++ generic facilities such as std::invocable and std::invoke_result_t.
Proposed changes
Audit callable execution paths, especially:
detail::apply_impl;
detail::fun_ptr_wrapper::operator();
- any direct calls used by
evaluate, recursive_evaluate, or callable type deduction.
Replace direct calls with std::invoke where doing so expands conformance without changing intended recursive deferred semantics.
Example:
return std::invoke(
std::forward<F>(f),
std::get<I>(std::forward<Tuple>(t))()...);
Design considerations
- Add
<functional> only where directly required.
- Preserve perfect forwarding and
decltype(auto).
- Propagate
noexcept using the exact std::invoke expression.
- Align constraints and traits with the invocation mechanism, using
std::invocable or std::is_invocable_v consistently.
- Test member-function pointers with object references, pointers, and
std::reference_wrapper where supported by the surrounding deferred API.
- Test member-data pointers and reference-preserving return behavior.
- Determine whether
fun_ptr_wrapper remains necessary after adopting std::invoke; remove it only if public behavior and type traits remain compatible.
- Be cautious around
recursive_evaluate: broadening what counts as invocable may intentionally change which objects are recursively evaluated.
Compatibility
For existing ordinary callables this should be behavior-preserving. Newly accepted member pointers are additive, but type and noexcept behavior should be verified across supported compilers.
Acceptance criteria
Motivation
Several internal call paths use direct function-call syntax:
f(args...);Direct invocation supports ordinary functions and function objects, but not the full standard
INVOKEmodel.std::invokeuniformly supports:std::reference_wrappertargets.Using it would make deferred callable interfaces align with standard C++ generic facilities such as
std::invocableandstd::invoke_result_t.Proposed changes
Audit callable execution paths, especially:
detail::apply_impl;detail::fun_ptr_wrapper::operator();evaluate,recursive_evaluate, or callable type deduction.Replace direct calls with
std::invokewhere doing so expands conformance without changing intended recursive deferred semantics.Example:
return std::invoke( std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))()...);Design considerations
<functional>only where directly required.decltype(auto).noexceptusing the exactstd::invokeexpression.std::invocableorstd::is_invocable_vconsistently.std::reference_wrapperwhere supported by the surrounding deferred API.fun_ptr_wrapperremains necessary after adoptingstd::invoke; remove it only if public behavior and type traits remain compatible.recursive_evaluate: broadening what counts as invocable may intentionally change which objects are recursively evaluated.Compatibility
For existing ordinary callables this should be behavior-preserving. Newly accepted member pointers are additive, but type and
noexceptbehavior should be verified across supported compilers.Acceptance criteria
std::invokeat the appropriate callable boundary.decltype(auto)behavior are covered by compile-time tests.noexceptreflects the underlying invocation.