@@ -268,6 +268,13 @@ class cpp_function : public function {
268
268
rec->is_constructor = !strcmp (rec->name , " __init__" ) || !strcmp (rec->name , " __setstate__" );
269
269
rec->nargs = (std::uint16_t ) args;
270
270
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
+
271
278
#if PY_MAJOR_VERSION < 3
272
279
if (rec->sibling && PyMethod_Check (rec->sibling .ptr ()))
273
280
rec->sibling = PyMethod_GET_FUNCTION (rec->sibling .ptr ());
@@ -399,8 +406,10 @@ class cpp_function : public function {
399
406
using namespace detail ;
400
407
401
408
/* 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; // Stores the one we actually use
404
413
405
414
/* Need to know how many arguments + keyword arguments there are to pick the right overload */
406
415
const size_t n_args_in = (size_t ) PyTuple_GET_SIZE (args_in);
@@ -444,15 +453,21 @@ class cpp_function : public function {
444
453
if (func.has_args ) --pos_args; // (but don't count py::args
445
454
if (func.has_kwargs ) --pos_args; // or py::kwargs)
446
455
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)
448
463
continue ; // Too many arguments for this overload
449
464
450
- if (n_args_in < pos_args && func.args .size () < pos_args)
465
+ if (n_args < pos_args && func.args .size () < pos_args)
451
466
continue ; // Not enough arguments given, and not enough defaults to fill in the blanks
452
467
453
468
function_call call (func, parent);
454
469
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 );
456
471
size_t args_copied = 0 ;
457
472
458
473
// 1. Copy any position arguments given.
@@ -464,7 +479,7 @@ class cpp_function : public function {
464
479
break ;
465
480
}
466
481
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 ));
468
483
call.args_convert .push_back (args_copied < func.args .size () ? func.args [args_copied].convert : true );
469
484
}
470
485
if (bad_kwarg)
@@ -524,7 +539,7 @@ class cpp_function : public function {
524
539
size_t args_size = n_args_in - args_copied;
525
540
extra_args = tuple (args_size);
526
541
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 );
528
543
extra_args[i] = item.inc_ref ().ptr ();
529
544
}
530
545
}
@@ -563,8 +578,10 @@ class cpp_function : public function {
563
578
result = PYBIND11_TRY_NEXT_OVERLOAD;
564
579
}
565
580
566
- if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD)
581
+ if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD) {
582
+ winner = &func;
567
583
break ;
584
+ }
568
585
569
586
if (overloaded) {
570
587
// The (overloaded) call failed; if the call has at least one argument that
@@ -591,8 +608,10 @@ class cpp_function : public function {
591
608
result = PYBIND11_TRY_NEXT_OVERLOAD;
592
609
}
593
610
594
- if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD)
611
+ if (result.ptr () != PYBIND11_TRY_NEXT_OVERLOAD) {
612
+ winner = const_cast <function_record *>(&call.func );
595
613
break ;
614
+ }
596
615
}
597
616
}
598
617
} catch (error_already_set &e) {
@@ -638,20 +657,32 @@ class cpp_function : public function {
638
657
msg += " " + std::to_string (++ctr) + " . " ;
639
658
640
659
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 ) {
643
661
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...)`
648
682
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);
655
686
wrote_sig = true ;
656
687
}
657
688
}
@@ -690,12 +721,46 @@ class cpp_function : public function {
690
721
msg += it->signature ;
691
722
PyErr_SetString (PyExc_TypeError, msg.c_str ());
692
723
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 ) {
697
726
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
+ }
699
764
}
700
765
return result.ptr ();
701
766
}
@@ -1131,10 +1196,15 @@ class class_ : public detail::generic_type {
1131
1196
}
1132
1197
}
1133
1198
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) {
1136
1202
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 );
1138
1208
}
1139
1209
1140
1210
static void dealloc (PyObject *inst_) {
0 commit comments