1313#include " detail/dynamic_raw_ptr_cast_if_possible.h"
1414#include " detail/exception_translation.h"
1515#include " detail/function_record_pyobject.h"
16+ #include " detail/function_ref.h"
1617#include " detail/init.h"
1718#include " detail/native_enum_data.h"
1819#include " detail/using_smart_holder.h"
@@ -379,6 +380,40 @@ class cpp_function : public function {
379380 return unique_function_record (new detail::function_record ());
380381 }
381382
383+ private:
384+ // This is outlined from the dispatch lambda in initialize to save
385+ // on code size. Crucially, we use function_ref to type-erase the
386+ // actual function lambda so that we can get code reuse for
387+ // functions with the same Return, Args, and Guard.
388+ template <typename Return, typename Guard, typename ArgsConverter, typename ... Args>
389+ static handle call_impl (detail::function_call &call, detail::function_ref<Return (Args...)> f) {
390+ using namespace detail ;
391+ using cast_out
392+ = make_caster<conditional_t <std::is_void<Return>::value, void_type, Return>>;
393+
394+ ArgsConverter args_converter;
395+ if (!args_converter.load_args (call)) {
396+ return PYBIND11_TRY_NEXT_OVERLOAD;
397+ }
398+
399+ /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
400+ return_value_policy policy
401+ = return_value_policy_override<Return>::policy (call.func .policy );
402+
403+ /* Perform the function call */
404+ handle result;
405+ if (call.func .is_setter ) {
406+ (void ) std::move (args_converter).template call <Return, Guard>(f);
407+ result = none ().release ();
408+ } else {
409+ result = cast_out::cast (
410+ std::move (args_converter).template call <Return, Guard>(f), policy, call.parent );
411+ }
412+
413+ return result;
414+ }
415+
416+ protected:
382417 // / Special internal constructor for functors, lambda functions, etc.
383418 template <typename Func, typename Return, typename ... Args, typename ... Extra>
384419 void initialize (Func &&f, Return (*)(Args...), const Extra &...extra ) {
@@ -441,13 +476,6 @@ class cpp_function : public function {
441476
442477 /* Dispatch code which converts function arguments and performs the actual function call */
443478 rec->impl = [](function_call &call) -> handle {
444- cast_in args_converter;
445-
446- /* Try to cast the function arguments into the C++ domain */
447- if (!args_converter.load_args (call)) {
448- return PYBIND11_TRY_NEXT_OVERLOAD;
449- }
450-
451479 /* Invoke call policy pre-call hook */
452480 process_attributes<Extra...>::precall (call);
453481
@@ -456,24 +484,11 @@ class cpp_function : public function {
456484 : call.func .data [0 ]);
457485 auto *cap = const_cast <capture *>(reinterpret_cast <const capture *>(data));
458486
459- /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */
460- return_value_policy policy
461- = return_value_policy_override<Return>::policy (call.func .policy );
462-
463- /* Function scope guard -- defaults to the compile-to-nothing `void_type` */
464- using Guard = extract_guard_t <Extra...>;
465-
466- /* Perform the function call */
467- handle result;
468- if (call.func .is_setter ) {
469- (void ) std::move (args_converter).template call <Return, Guard>(cap->f );
470- result = none ().release ();
471- } else {
472- result = cast_out::cast (
473- std::move (args_converter).template call <Return, Guard>(cap->f ),
474- policy,
475- call.parent );
476- }
487+ auto result = call_impl<Return,
488+ /* Function scope guard -- defaults to the compile-to-nothing
489+ `void_type` */
490+ extract_guard_t <Extra...>,
491+ cast_in>(call, detail::function_ref<Return (Args...)>(cap->f ));
477492
478493 /* Invoke call policy post-call hook */
479494 process_attributes<Extra...>::postcall (call, result);
0 commit comments