Skip to content

Commit dff76b8

Browse files
committed
Allow specializations based on callback function return values.
1 parent 654fe92 commit dff76b8

File tree

1 file changed

+43
-34
lines changed

1 file changed

+43
-34
lines changed

include/pybind11/functional.h

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,47 @@
1515

1616
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
1717
PYBIND11_NAMESPACE_BEGIN(detail)
18+
PYBIND11_NAMESPACE_BEGIN(type_caster_std_function_specializations)
19+
20+
// ensure GIL is held during functor destruction
21+
struct func_handle {
22+
function f;
23+
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
24+
// This triggers a syntax error under very special conditions (very weird indeed).
25+
explicit
26+
#endif
27+
func_handle(function &&f_) noexcept
28+
: f(std::move(f_)) {
29+
}
30+
func_handle(const func_handle &f_) { operator=(f_); }
31+
func_handle &operator=(const func_handle &f_) {
32+
gil_scoped_acquire acq;
33+
f = f_.f;
34+
return *this;
35+
}
36+
~func_handle() {
37+
gil_scoped_acquire acq;
38+
function kill_f(std::move(f));
39+
}
40+
};
41+
42+
// to emulate 'move initialization capture' in C++11
43+
struct func_wrapper_base {
44+
func_handle hfunc;
45+
explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
46+
};
47+
48+
template <typename Return, typename... Args>
49+
struct func_wrapper : func_wrapper_base {
50+
using func_wrapper_base::func_wrapper_base;
51+
Return operator()(Args... args) const {
52+
gil_scoped_acquire acq;
53+
// casts the returned object as a rvalue to the return type
54+
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
55+
}
56+
};
57+
58+
PYBIND11_NAMESPACE_END(type_caster_std_function_specializations)
1859

1960
template <typename Return, typename... Args>
2061
struct type_caster<std::function<Return(Args...)>> {
@@ -77,40 +118,8 @@ struct type_caster<std::function<Return(Args...)>> {
77118
// See PR #1413 for full details
78119
}
79120

80-
// ensure GIL is held during functor destruction
81-
struct func_handle {
82-
function f;
83-
#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))
84-
// This triggers a syntax error under very special conditions (very weird indeed).
85-
explicit
86-
#endif
87-
func_handle(function &&f_) noexcept
88-
: f(std::move(f_)) {
89-
}
90-
func_handle(const func_handle &f_) { operator=(f_); }
91-
func_handle &operator=(const func_handle &f_) {
92-
gil_scoped_acquire acq;
93-
f = f_.f;
94-
return *this;
95-
}
96-
~func_handle() {
97-
gil_scoped_acquire acq;
98-
function kill_f(std::move(f));
99-
}
100-
};
101-
102-
// to emulate 'move initialization capture' in C++11
103-
struct func_wrapper {
104-
func_handle hfunc;
105-
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
106-
Return operator()(Args... args) const {
107-
gil_scoped_acquire acq;
108-
// casts the returned object as a rvalue to the return type
109-
return hfunc.f(std::forward<Args>(args)...).template cast<Return>();
110-
}
111-
};
112-
113-
value = func_wrapper(func_handle(std::move(func)));
121+
value = type_caster_std_function_specializations::func_wrapper<Return, Args...>(
122+
type_caster_std_function_specializations::func_handle(std::move(func)));
114123
return true;
115124
}
116125

0 commit comments

Comments
 (0)