@@ -199,104 +199,78 @@ template <typename... Args> struct alias_constructor {
199
199
};
200
200
201
201
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
202
- template <typename CFunc, typename AFuncIn, typename ... Args>
203
- struct factory {
204
- private:
205
- using CFuncType = typename std::remove_reference<CFunc>::type;
206
- using AFunc = conditional_t <std::is_void<AFuncIn>::value, void_type, AFuncIn>;
207
- using AFuncType = typename std::remove_reference<AFunc>::type;
202
+ template <typename CFunc, typename AFunc = void_type (*)(),
203
+ typename = function_signature_t <CFunc>, typename = function_signature_t <AFunc>>
204
+ struct factory ;
205
+
206
+ // Specialization for py::init(Func)
207
+ template <typename Func, typename Return, typename ... Args>
208
+ struct factory <Func, void_type (*)(), Return(Args...)> {
209
+ remove_reference_t <Func> class_factory;
208
210
209
- CFuncType class_factory;
210
- AFuncType alias_factory;
211
+ factory (Func &&f) : class_factory(std::forward<Func>(f)) { }
211
212
212
- public:
213
- // Constructor with a single function/lambda to call; for classes without aliases or with
214
- // aliases that can be move constructed from the base.
215
- factory (CFunc &&f) : class_factory(std::forward<CFunc>(f)) {}
216
-
217
- // Constructor with two functions/lambdas, for a class with distinct class/alias factories: the
218
- // first is called when an alias is not needed, the second when the alias is needed. Requires
219
- // non-void AFunc.
220
- factory (CFunc &&c, AFunc &&a) :
221
- class_factory (std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
222
-
223
- // Add __init__ definition for a class that either has no alias or has no separate alias
224
- // factory; this always constructs the class itself. If the class is registered with an alias
213
+ // The given class either has no alias or has no separate alias factory;
214
+ // this always constructs the class itself. If the class is registered with an alias
225
215
// type and an alias instance is needed (i.e. because the final type is a Python class
226
216
// inheriting from the C++ type) the returned value needs to either already be an alias
227
217
// instance, or the alias needs to be constructible from a `Class &&` argument.
228
- template <typename Class, typename ... Extra,
229
- enable_if_t <!Class::has_alias || std::is_void<AFuncIn>::value, int > = 0 >
230
- void execute (Class &cl, const Extra&... extra) && {
218
+ template <typename Class, typename ... Extra>
219
+ void execute (Class &cl, const Extra &...extra) && {
231
220
#if defined(PYBIND11_CPP14)
232
221
cl.def (" __init__" , [func = std::move (class_factory)]
233
222
#else
234
- CFuncType &func = class_factory;
223
+ auto &func = class_factory;
235
224
cl.def (" __init__" , [func]
236
225
#endif
237
226
(value_and_holder &v_h, Args... args) {
238
227
construct<Class>(v_h, func (std::forward<Args>(args)...),
239
228
Py_TYPE (v_h.inst ) != v_h.type ->type );
240
229
}, is_new_style_constructor (), extra...);
241
230
}
231
+ };
242
232
243
- // Add __init__ definition for a class with an alias *and* distinct alias factory; the former is
244
- // called when the `self` type passed to `__init__` is the direct class (i.e. not inherited), the latter
245
- // when `self` is a Python-side subtype.
246
- template <typename Class, typename ... Extra,
247
- enable_if_t <Class::has_alias && !std::is_void<AFuncIn>::value, int > = 0 >
233
+ // Specialization for py::init(Func, AliasFunc)
234
+ template <typename CFunc, typename AFunc,
235
+ typename CReturn, typename ... CArgs, typename AReturn, typename ... AArgs>
236
+ struct factory <CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
237
+ static_assert (sizeof ...(CArgs) == sizeof ...(AArgs),
238
+ " pybind11::init(class_factory, alias_factory): class and alias factories "
239
+ " must have identical argument signatures" );
240
+ static_assert (all_of<std::is_same<CArgs, AArgs>...>::value,
241
+ " pybind11::init(class_factory, alias_factory): class and alias factories "
242
+ " must have identical argument signatures" );
243
+
244
+ remove_reference_t <CFunc> class_factory;
245
+ remove_reference_t <AFunc> alias_factory;
246
+
247
+ factory (CFunc &&c, AFunc &&a)
248
+ : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) { }
249
+
250
+ // The class factory is called when the `self` type passed to `__init__` is the direct
251
+ // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
252
+ template <typename Class, typename ... Extra>
248
253
void execute (Class &cl, const Extra&... extra) && {
254
+ static_assert (Class::has_alias, " The two-argument version of `py::init()` can "
255
+ " only be used if the class has an alias" );
249
256
#if defined(PYBIND11_CPP14)
250
257
cl.def (" __init__" , [class_func = std::move (class_factory), alias_func = std::move (alias_factory)]
251
258
#else
252
- CFuncType &class_func = class_factory;
253
- AFuncType &alias_func = alias_factory;
259
+ auto &class_func = class_factory;
260
+ auto &alias_func = alias_factory;
254
261
cl.def (" __init__" , [class_func, alias_func]
255
262
#endif
256
- (value_and_holder &v_h, Args ... args) {
263
+ (value_and_holder &v_h, CArgs ... args) {
257
264
if (Py_TYPE (v_h.inst ) == v_h.type ->type )
258
265
// If the instance type equals the registered type we don't have inheritance, so
259
266
// don't need the alias and can construct using the class function:
260
- construct<Class>(v_h, class_func (std::forward<Args >(args)...), false );
267
+ construct<Class>(v_h, class_func (std::forward<CArgs >(args)...), false );
261
268
else
262
- construct<Class>(v_h, alias_func (std::forward<Args >(args)...), true );
269
+ construct<Class>(v_h, alias_func (std::forward<CArgs >(args)...), true );
263
270
}, is_new_style_constructor (), extra...);
264
271
}
265
272
};
266
273
267
- template <typename Func> using functype =
268
- conditional_t <std::is_function<remove_reference_t <Func>>::value, remove_reference_t <Func> *,
269
- conditional_t <is_function_pointer<remove_reference_t <Func>>::value, remove_reference_t <Func>,
270
- Func>>;
271
-
272
- // Helper definition to infer the detail::initimpl::factory template types from a callable object
273
- template <typename Func, typename Return, typename ... Args>
274
- factory<functype<Func>, void , Args...> func_decltype (Return (*)(Args...));
275
-
276
- // metatemplate that ensures the Class and Alias factories take identical arguments: we need to be
277
- // able to call either one with the given arguments (depending on the final instance type).
278
- template <typename Return1, typename Return2, typename ... Args1, typename ... Args2>
279
- inline constexpr bool require_matching_arguments (Return1 (*)(Args1...), Return2 (*)(Args2...)) {
280
- static_assert (sizeof ...(Args1) == sizeof ...(Args2),
281
- " pybind11::init(class_factory, alias_factory): class and alias factories must have identical argument signatures" );
282
- static_assert (all_of<std::is_same<Args1, Args2>...>::value,
283
- " pybind11::init(class_factory, alias_factory): class and alias factories must have identical argument signatures" );
284
- return true ;
285
- }
286
-
287
- // Unimplemented function provided only for its type signature (via `decltype`), which resolves to
288
- // the appropriate specialization of the above `init` struct with the appropriate function, argument
289
- // and return types.
290
- template <typename CFunc, typename AFunc,
291
- typename CReturn, typename ... CArgs, typename AReturn, typename ... AArgs,
292
- bool = require_matching_arguments((CReturn (*)(CArgs...)) nullptr , (AReturn (*)(AArgs...)) nullptr )>
293
- factory<functype<CFunc>, functype<AFunc>, CArgs...> func_decltype (CReturn (*)(CArgs...), AReturn (*)(AArgs...));
294
-
295
- // Resolves to the appropriate specialization of the `pybind11::detail::initimpl::factory<...>` for a
296
- // given init function or pair of class/alias init functions.
297
- template <typename ... Func> using factory_t = decltype(func_decltype<Func...>(
298
- (function_signature_t <Func> *) nullptr ...));
299
-
300
274
NAMESPACE_END (initimpl)
301
275
NAMESPACE_END(detail)
302
276
NAMESPACE_END(pybind11)
0 commit comments