@@ -268,6 +268,13 @@ class cpp_function : public function {
268268 rec->is_constructor = !strcmp (rec->name , " __init__" ) || !strcmp (rec->name , " __setstate__" );
269269 rec->nargs = (std::uint16_t ) args;
270270
271+ if (rec->is_constructor && !rec->is_method ) {
272+ // Handle a def_static(__init__) constructor: we expose this to Python as an instance
273+ // method, then deal with the static call internally.
274+ rec->is_factory_constructor = true ;
275+ rec->is_method = true ;
276+ }
277+
271278#if PY_MAJOR_VERSION < 3
272279 if (rec->sibling && PyMethod_Check (rec->sibling .ptr ()))
273280 rec->sibling = PyMethod_GET_FUNCTION (rec->sibling .ptr ());
@@ -399,8 +406,10 @@ class cpp_function : public function {
399406 using namespace detail ;
400407
401408 /* Iterator over the list of potentially admissible overloads */
402- function_record *overloads = (function_record *) PyCapsule_GetPointer (self, nullptr ),
403- *it = overloads;
409+ auto func_capsule = reinterpret_borrow<capsule>(self);
410+ function_record *overloads = func_capsule,
411+ *it = overloads,
412+ *winner = nullptr ; // Stores the one we actually use
404413
405414 /* Need to know how many arguments + keyword arguments there are to pick the right overload */
406415 const size_t n_args_in = (size_t ) PyTuple_GET_SIZE (args_in);
@@ -444,15 +453,21 @@ class cpp_function : public function {
444453 if (func.has_args ) --pos_args; // (but don't count py::args
445454 if (func.has_kwargs ) --pos_args; // or py::kwargs)
446455
447- if (!func.has_args && n_args_in > pos_args)
456+ // If this overload is a factory function masquerading as a constructor we need to
457+ // skip the initial (uninitialized) self argument.
458+ bool skip_first = func.is_factory_constructor ;
459+
460+ const size_t n_args = n_args_in - skip_first;
461+
462+ if (!func.has_args && n_args > pos_args)
448463 continue ; // Too many arguments for this overload
449464
450- if (n_args_in < pos_args && func.args .size () < pos_args)
465+ if (n_args < pos_args && func.args .size () < pos_args)
451466 continue ; // Not enough arguments given, and not enough defaults to fill in the blanks
452467
453468 function_call call (func, parent);
454469
455- size_t args_to_copy = std::min (pos_args, n_args_in );
470+ size_t args_to_copy = std::min (pos_args, n_args );
456471 size_t args_copied = 0 ;
457472
458473 // 1. Copy any position arguments given.
@@ -464,7 +479,7 @@ class cpp_function : public function {
464479 break ;
465480 }
466481
467- call.args .push_back (PyTuple_GET_ITEM (args_in, args_copied));
482+ call.args .push_back (PyTuple_GET_ITEM (args_in, args_copied + skip_first ));
468483 call.args_convert .push_back (args_copied < func.args .size () ? func.args [args_copied].convert : true );
469484 }
470485 if (bad_kwarg)
@@ -524,7 +539,7 @@ class cpp_function : public function {
524539 size_t args_size = n_args_in - args_copied;
525540 extra_args = tuple (args_size);
526541 for (size_t i = 0 ; i < args_size; ++i) {
527- handle item = PyTuple_GET_ITEM (args_in, args_copied + i);
542+ handle item = PyTuple_GET_ITEM (args_in, args_copied + i + skip_first );
528543 extra_args[i] = item.inc_ref ().ptr ();
529544 }
530545 }
@@ -563,8 +578,10 @@ class cpp_function : public function {
563578 result = PYBIND11_TRY_NEXT_OVERLOAD;
564579 }
565580
566- if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD)
581+ if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD) {
582+ winner = &func;
567583 break ;
584+ }
568585
569586 if (overloaded) {
570587 // The (overloaded) call failed; if the call has at least one argument that
@@ -591,8 +608,10 @@ class cpp_function : public function {
591608 result = PYBIND11_TRY_NEXT_OVERLOAD;
592609 }
593610
594- if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD)
611+ if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD) {
612+ winner = const_cast <function_record *>(&call.func );
595613 break ;
614+ }
596615 }
597616 }
598617 } catch (error_already_set &e) {
@@ -638,20 +657,32 @@ class cpp_function : public function {
638657 msg += " " + std::to_string (++ctr) + " . " ;
639658
640659 bool wrote_sig = false ;
641- if (overloads->is_constructor ) {
642- // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)`
660+ if (it2->is_constructor ) {
643661 std::string sig = it2->signature ;
644- size_t start = sig.find (' (' ) + 7 ; // skip "(self: "
645- if (start < sig.size ()) {
646- // End at the , for the next argument
647- size_t end = sig.find (" , " ), next = end + 2 ;
662+ if (!it2->is_factory_constructor ) {
663+ // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as `Object(arg0, ...)`
664+ size_t start = sig.find (' (' ) + 7 ; // skip "(self: "
665+ if (start < sig.size ()) {
666+ // End at the , for the next argument
667+ size_t end = sig.find (" , " ), next = end + 2 ;
668+ size_t ret = sig.rfind (" -> " );
669+ // Or the ), if there is no comma:
670+ if (end >= sig.size ()) next = end = sig.find (' )' );
671+ if (start < end && next < sig.size ()) {
672+ msg.append (sig, start, end - start);
673+ msg += ' (' ;
674+ msg.append (sig, next, ret - next);
675+ wrote_sig = true ;
676+ }
677+ }
678+ }
679+ else {
680+ // A factory function masquerading as a constructor; rewrite
681+ // `(arg0: whatever...) -> ClassName` as `ClassName(arg0: whatever...)`
648682 size_t ret = sig.rfind (" -> " );
649- // Or the ), if there is no comma:
650- if (end >= sig.size ()) next = end = sig.find (' )' );
651- if (start < end && next < sig.size ()) {
652- msg.append (sig, start, end - start);
653- msg += ' (' ;
654- msg.append (sig, next, ret - next);
683+ if (ret < sig.size ()) {
684+ msg.append (sig, ret + 4 , sig.npos );
685+ msg.append (sig, 0 , ret);
655686 wrote_sig = true ;
656687 }
657688 }
@@ -690,12 +721,46 @@ class cpp_function : public function {
690721 msg += it->signature ;
691722 PyErr_SetString (PyExc_TypeError, msg.c_str ());
692723 return nullptr ;
693- } else {
694- if (overloads->is_constructor ) {
695- /* When a constructor ran successfully, the corresponding
696- holder type (e.g. std::unique_ptr) must still be initialized. */
724+ } else { // Call succeeded
725+ if (winner->is_constructor ) {
697726 auto tinfo = get_type_info (Py_TYPE (parent.ptr ()));
698- tinfo->init_holder (parent.ptr (), nullptr );
727+ if (!winner->is_factory_constructor ) {
728+ /* When an ordinary constructor ran successfully, the corresponding
729+ holder type (e.g. std::unique_ptr) must still be initialized. */
730+ tinfo->init_holder (parent.ptr (), nullptr , nullptr );
731+ }
732+ else {
733+ /* For a factory function exposed as a constructor, the corresponding pointer
734+ and holder must be transferred from the returned object into the allocated
735+ instance */
736+ auto *result_inst = (detail::instance_essentials<void > *) result.ptr (),
737+ *parent_inst = (detail::instance_essentials<void > *) parent.ptr ();
738+ std::string failure;
739+ // Make sure the factory function gave us exactly the right type:
740+ if (Py_TYPE (result.ptr ()) != tinfo->type )
741+ failure = std::string (" static __init__() should return '" ) + tinfo->type ->tp_name +
742+ " ', not '" + Py_TYPE (result.ptr ())->tp_name + " '" ;
743+ // The factory function must give back a unique reference:
744+ else if (result.ref_count () != 1 )
745+ failure = " static __init__() returned an object with multiple references" ;
746+ // Guard against accidentally specifying a reference r.v. policy or similar:
747+ else if (!result_inst->holder_constructed && !result_inst->owned )
748+ failure = " static __init__() failed: cannot construct from an unowned reference" ;
749+
750+ if (!failure.empty ()) {
751+ result.dec_ref ();
752+ PyErr_SetString (PyExc_TypeError, failure.c_str ());
753+ return nullptr ;
754+ }
755+
756+ // Swap the pointer and other internals, then transfer the holder:
757+ detail::instance_swap (result_inst, parent_inst);
758+ tinfo->init_holder (parent.ptr (), nullptr , result.ptr ());
759+ // We transfered the value out of result, so let it be destroyed:
760+ result.dec_ref ();
761+
762+ result = none ().release ();
763+ }
699764 }
700765 return result.ptr ();
701766 }
@@ -1131,10 +1196,15 @@ class class_ : public detail::generic_type {
11311196 }
11321197 }
11331198
1134- // / Initialize holder object of an instance, possibly given a pointer to an existing holder
1135- static void init_holder (PyObject *inst_, const void *holder_ptr) {
1199+ // / Initialize holder object of an instance, possibly given a pointer to an existing holder or
1200+ // / an alternative instance to transfer the holder from
1201+ static void init_holder (PyObject *inst_, const void *holder_in, PyObject *holder_from) {
11361202 auto inst = (instance_type *) inst_;
1137- init_holder_helper (inst, (const holder_type *) holder_ptr, inst->value );
1203+ const holder_type *holder_ptr = (const holder_type *) holder_in;
1204+ if (!holder_ptr && holder_from)
1205+ holder_ptr = &((instance_type *) holder_from)->holder ;
1206+
1207+ init_holder_helper (inst, holder_ptr, inst->value );
11381208 }
11391209
11401210 static void dealloc (PyObject *inst_) {
0 commit comments