Coverage Report

Created: 2026-10-28 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pybind11/include/pybind11/detail/init.h
Line
Count
Source
1
/*
2
    pybind11/detail/init.h: init factory function implementation and support code.
3
4
    Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>
5
6
    All rights reserved. Use of this source code is governed by a
7
    BSD-style license that can be found in the LICENSE file.
8
*/
9
10
#pragma once
11
12
#include "class.h"
13
#include "using_smart_holder.h"
14
15
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
16
17
PYBIND11_WARNING_DISABLE_MSVC(4127)
18
19
PYBIND11_NAMESPACE_BEGIN(detail)
20
21
template <>
22
class type_caster<value_and_holder> {
23
public:
24
0
    bool load(handle h, bool) {
25
0
        value = reinterpret_cast<value_and_holder *>(h.ptr());
26
0
        return true;
27
0
    }
28
29
    template <typename>
30
    using cast_op_type = value_and_holder &;
31
0
    explicit operator value_and_holder &() { return *value; }
32
    static constexpr auto name = const_name<value_and_holder>();
33
34
private:
35
    value_and_holder *value = nullptr;
36
};
37
38
PYBIND11_NAMESPACE_BEGIN(initimpl)
39
40
0
inline void no_nullptr(const void *ptr) {
41
0
    if (!ptr) {
42
0
        throw type_error("pybind11::init(): factory function returned nullptr");
43
0
    }
44
0
}
45
46
// Implementing functions for all forms of py::init<...> and py::init(...)
47
template <typename Class>
48
using Cpp = typename Class::type;
49
template <typename Class>
50
using Alias = typename Class::type_alias;
51
template <typename Class>
52
using Holder = typename Class::holder_type;
53
54
template <typename Class>
55
using is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;
56
57
// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.
58
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
59
bool is_alias(Cpp<Class> *ptr) {
60
    return dynamic_cast<Alias<Class> *>(ptr) != nullptr;
61
}
62
// Failing fallback version of the above for a no-alias class (always returns false)
63
template <typename /*Class*/>
64
constexpr bool is_alias(const void *) {
65
    return false;
66
}
67
68
// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall
69
// back to brace aggregate initialization so that for aggregate initialization can be used with
70
// py::init, e.g.  `py::init<int, int>` to initialize a `struct T { int a; int b; }`.  For
71
// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually
72
// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).
73
template <typename Class,
74
          typename... Args,
75
          detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>
76
inline Class *construct_or_initialize(Args &&...args) {
77
    return new Class(std::forward<Args>(args)...);
78
}
79
template <typename Class,
80
          typename... Args,
81
          detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>
82
inline Class *construct_or_initialize(Args &&...args) {
83
    return new Class{std::forward<Args>(args)...};
84
}
85
86
// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with
87
// an alias to provide only a single Cpp factory function as long as the Alias can be
88
// constructed from an rvalue reference of the base Cpp type.  This means that Alias classes
89
// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to
90
// inherit all the base class constructors.
91
template <typename Class>
92
void construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,
93
                              value_and_holder &v_h,
94
                              Cpp<Class> &&base) {
95
    v_h.value_ptr() = new Alias<Class>(std::move(base));
96
}
97
template <typename Class>
98
[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,
99
                                           value_and_holder &,
100
                                           Cpp<Class> &&) {
101
    throw type_error("pybind11::init(): unable to convert returned instance to required "
102
                     "alias class: no `Alias<Class>(Class &&)` constructor available");
103
}
104
105
// Error-generating fallback for factories that don't match one of the below construction
106
// mechanisms.
107
template <typename Class>
108
void construct(...) {
109
    static_assert(!std::is_same<Class, Class>::value /* always false */,
110
                  "pybind11::init(): init function must return a compatible pointer, "
111
                  "holder, or value");
112
}
113
114
// Pointer return v1: the factory function returns a class pointer for a registered class.
115
// If we don't need an alias (because this class doesn't have one, or because the final type is
116
// inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to
117
// construct an Alias from the returned base instance.
118
template <typename Class>
119
void construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {
120
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
121
    no_nullptr(ptr);
122
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
123
        // We're going to try to construct an alias by moving the cpp type.  Whether or not
124
        // that succeeds, we still need to destroy the original cpp pointer (either the
125
        // moved away leftover, if the alias construction works, or the value itself if we
126
        // throw an error), but we can't just call `delete ptr`: it might have a special
127
        // deleter, or might be shared_from_this.  So we construct a holder around it as if
128
        // it was a normal instance, then steal the holder away into a local variable; thus
129
        // the holder and destruction happens when we leave the C++ scope, and the holder
130
        // class gets to handle the destruction however it likes.
131
        v_h.value_ptr() = ptr;
132
        v_h.set_instance_registered(true); // Trick to prevent init_instance from registering it
133
        // DANGER ZONE BEGIN: exceptions will leave v_h in an invalid state.
134
        v_h.type->init_instance(v_h.inst, nullptr);                        // Set up the holder
135
        Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder
136
        v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null
137
        v_h.set_instance_registered(false);
138
        // DANGER ZONE END.
139
140
        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));
141
    } else {
142
        // Otherwise the type isn't inherited, so we don't need an Alias
143
        v_h.value_ptr() = ptr;
144
    }
145
}
146
147
// Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over
148
// ownership of the pointer.
149
template <typename Class, enable_if_t<Class::has_alias, int> = 0>
150
void construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {
151
    no_nullptr(alias_ptr);
152
    v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);
153
}
154
155
// Holder return: copy its pointer, and move or copy the returned holder into the new instance's
156
// holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a
157
// derived type (through those holder's implicit conversion from derived class holder
158
// constructors).
159
template <typename Class, detail::enable_if_t<!is_smart_holder<Holder<Class>>::value, int> = 0>
160
void construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {
161
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
162
    auto *ptr = holder_helper<Holder<Class>>::get(holder);
163
    no_nullptr(ptr);
164
    // If we need an alias, check that the held pointer is actually an alias instance
165
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
166
        throw type_error("pybind11::init(): construction failed: returned holder-wrapped instance "
167
                         "is not an alias instance");
168
    }
169
170
    // Cast away constness to store in void* storage.
171
    // The value_and_holder storage is fundamentally untyped (void**), so we lose
172
    // const-correctness here by design. The const qualifier will be restored
173
    // when the pointer is later retrieved and cast back to the original type.
174
    // This explicit const_cast makes the const-removal clearly visible.
175
    v_h.value_ptr() = const_cast<void *>(static_cast<const void *>(ptr));
176
    v_h.type->init_instance(v_h.inst, &holder);
177
}
178
179
// return-by-value version 1: returning a cpp class by value.  If the class has an alias and an
180
// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct
181
// the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't
182
// need it, we simply move-construct the cpp value into a new instance.
183
template <typename Class>
184
void construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {
185
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
186
    static_assert(is_move_constructible<Cpp<Class>>::value,
187
                  "pybind11::init() return-by-value factory function requires a movable class");
188
    if (Class::has_alias && need_alias) {
189
        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));
190
    } else {
191
        v_h.value_ptr() = new Cpp<Class>(std::move(result));
192
    }
193
}
194
195
// return-by-value version 2: returning a value of the alias type itself.  We move-construct an
196
// Alias instance (even if no the python-side inheritance is involved).  The is intended for
197
// cases where Alias initialization is always desired.
198
template <typename Class>
199
void construct(value_and_holder &v_h, Alias<Class> &&result, bool) {
200
    static_assert(
201
        is_move_constructible<Alias<Class>>::value,
202
        "pybind11::init() return-by-alias-value factory function requires a movable alias class");
203
    v_h.value_ptr() = new Alias<Class>(std::move(result));
204
}
205
206
template <typename T, typename D>
207
smart_holder init_smart_holder_from_unique_ptr(std::unique_ptr<T, D> &&unq_ptr,
208
                                               bool void_cast_raw_ptr) {
209
    return smart_holder::from_unique_ptr(
210
        std::move(unq_ptr), /*mi_subobject_ptr*/ nullptr, void_cast_raw_ptr);
211
}
212
213
template <typename Class,
214
          typename D = std::default_delete<Cpp<Class>>,
215
          detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
216
void construct(value_and_holder &v_h, std::unique_ptr<Cpp<Class>, D> &&unq_ptr, bool need_alias) {
217
    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);
218
    auto *ptr = unq_ptr.get();
219
    no_nullptr(ptr);
220
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
221
        throw type_error("pybind11::init(): construction failed: returned std::unique_ptr pointee "
222
                         "is not an alias instance");
223
    }
224
    // Here and below: if the new object is a trampoline, the shared_from_this mechanism needs
225
    // to be prevented from accessing the smart_holder vptr, because it does not keep the
226
    // trampoline Python object alive. For types that don't inherit from enable_shared_from_this
227
    // it does not matter if void_cast_raw_ptr is true or false, therefore it's not necessary
228
    // to also inspect the type.
229
    auto smhldr = init_smart_holder_from_unique_ptr(
230
        std::move(unq_ptr), /*void_cast_raw_ptr*/ Class::has_alias && is_alias<Class>(ptr));
231
    v_h.value_ptr() = ptr;
232
    v_h.type->init_instance(v_h.inst, &smhldr);
233
}
234
235
template <typename Class,
236
          typename D = std::default_delete<Alias<Class>>,
237
          detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
238
void construct(value_and_holder &v_h,
239
               std::unique_ptr<Alias<Class>, D> &&unq_ptr,
240
               bool /*need_alias*/) {
241
    auto *ptr = unq_ptr.get();
242
    no_nullptr(ptr);
243
    auto smhldr
244
        = init_smart_holder_from_unique_ptr(std::move(unq_ptr), /*void_cast_raw_ptr*/ true);
245
    v_h.value_ptr() = ptr;
246
    v_h.type->init_instance(v_h.inst, &smhldr);
247
}
248
249
template <typename PtrType, typename Class>
250
void construct_from_shared_ptr(value_and_holder &v_h,
251
                               std::shared_ptr<PtrType> &&shd_ptr,
252
                               bool need_alias) {
253
    static_assert(std::is_same<PtrType, Cpp<Class>>::value
254
                      || std::is_same<PtrType, const Cpp<Class>>::value,
255
                  "Expected (const) Cpp<Class> as shared_ptr pointee");
256
    auto *ptr = shd_ptr.get();
257
    no_nullptr(ptr);
258
    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {
259
        throw type_error("pybind11::init(): construction failed: returned std::shared_ptr pointee "
260
                         "is not an alias instance");
261
    }
262
    // Cast to non-const if needed, consistent with internal design
263
    auto smhldr
264
        = smart_holder::from_shared_ptr(std::const_pointer_cast<Cpp<Class>>(std::move(shd_ptr)));
265
    v_h.value_ptr() = const_cast<Cpp<Class> *>(ptr);
266
    v_h.type->init_instance(v_h.inst, &smhldr);
267
}
268
269
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
270
void construct(value_and_holder &v_h, std::shared_ptr<Cpp<Class>> &&shd_ptr, bool need_alias) {
271
    construct_from_shared_ptr<Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
272
}
273
274
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
275
void construct(value_and_holder &v_h,
276
               std::shared_ptr<const Cpp<Class>> &&shd_ptr,
277
               bool need_alias) {
278
    construct_from_shared_ptr<const Cpp<Class>, Class>(v_h, std::move(shd_ptr), need_alias);
279
}
280
281
template <typename Class, detail::enable_if_t<is_smart_holder<Holder<Class>>::value, int> = 0>
282
void construct(value_and_holder &v_h,
283
               std::shared_ptr<Alias<Class>> &&shd_ptr,
284
               bool /*need_alias*/) {
285
    auto *ptr = shd_ptr.get();
286
    no_nullptr(ptr);
287
    auto smhldr = smart_holder::from_shared_ptr(shd_ptr);
288
    v_h.value_ptr() = ptr;
289
    v_h.type->init_instance(v_h.inst, &smhldr);
290
}
291
292
// Implementing class for py::init<...>()
293
template <typename... Args>
294
struct constructor {
295
    template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>
296
    static void execute(Class &cl, const Extra &...extra) {
297
        cl.def(
298
            "__init__",
299
            [](value_and_holder &v_h,
300
               Args... args) { // NOLINT(performance-unnecessary-value-param)
301
                v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
302
            },
303
            is_new_style_constructor(),
304
            extra...);
305
    }
306
307
    template <typename Class,
308
              typename... Extra,
309
              enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value,
310
                          int> = 0>
311
    static void execute(Class &cl, const Extra &...extra) {
312
        cl.def(
313
            "__init__",
314
            [](value_and_holder &v_h, Args... args) {
315
                if (Py_TYPE(v_h.inst) == v_h.type->type) {
316
                    v_h.value_ptr()
317
                        = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);
318
                } else {
319
                    v_h.value_ptr()
320
                        = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
321
                }
322
            },
323
            is_new_style_constructor(),
324
            extra...);
325
    }
326
327
    template <typename Class,
328
              typename... Extra,
329
              enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value,
330
                          int> = 0>
331
    static void execute(Class &cl, const Extra &...extra) {
332
        cl.def(
333
            "__init__",
334
            [](value_and_holder &v_h, Args... args) {
335
                v_h.value_ptr()
336
                    = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
337
            },
338
            is_new_style_constructor(),
339
            extra...);
340
    }
341
};
342
343
// Implementing class for py::init_alias<...>()
344
template <typename... Args>
345
struct alias_constructor {
346
    template <typename Class,
347
              typename... Extra,
348
              enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value,
349
                          int> = 0>
350
    static void execute(Class &cl, const Extra &...extra) {
351
        cl.def(
352
            "__init__",
353
            [](value_and_holder &v_h, Args... args) {
354
                v_h.value_ptr()
355
                    = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);
356
            },
357
            is_new_style_constructor(),
358
            extra...);
359
    }
360
};
361
362
// Implementation class for py::init(Func) and py::init(Func, AliasFunc)
363
template <typename CFunc,
364
          typename AFunc = void_type (*)(),
365
          typename = function_signature_t<CFunc>,
366
          typename = function_signature_t<AFunc>>
367
struct factory;
368
369
// Specialization for py::init(Func)
370
// Note: The 4th template parameter `void_type()` is explicitly specified to resolve a
371
// template ambiguity with the dual-factory specialization below when compiled with
372
// nvcc + GCC (see #5565). Without it, both specializations match equally well for the
373
// single-factory case, since the 4th parameter defaults to
374
// `function_signature_t<void_type(*)()>` = `void_type()`, which the dual-factory
375
// specialization can also decompose as `AReturn(AArgs...)` with `AReturn=void_type`
376
// and `AArgs={}`.
377
template <typename Func, typename Return, typename... Args>
378
struct factory<Func, void_type (*)(), Return(Args...), void_type()> {
379
    remove_reference_t<Func> class_factory;
380
381
    // NOLINTNEXTLINE(google-explicit-constructor)
382
    factory(Func &&f) : class_factory(std::forward<Func>(f)) {}
383
384
    // The given class either has no alias or has no separate alias factory;
385
    // this always constructs the class itself.  If the class is registered with an alias
386
    // type and an alias instance is needed (i.e. because the final type is a Python class
387
    // inheriting from the C++ type) the returned value needs to either already be an alias
388
    // instance, or the alias needs to be constructible from a `Class &&` argument.
389
    template <typename Class, typename... Extra>
390
    void execute(Class &cl, const Extra &...extra) && {
391
#if defined(__cpp_init_captures) && __cpp_init_captures >= 201304L
392
        cl.def(
393
            "__init__",
394
            [func = std::move(class_factory)]
395
#else
396
        auto &func = class_factory;
397
        cl.def(
398
            "__init__",
399
            [func]
400
#endif
401
            (value_and_holder &v_h, Args... args) {
402
                construct<Class>(
403
                    v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);
404
            },
405
            is_new_style_constructor(),
406
            extra...);
407
    }
408
};
409
410
// Specialization for py::init(Func, AliasFunc)
411
template <typename CFunc,
412
          typename AFunc,
413
          typename CReturn,
414
          typename... CArgs,
415
          typename AReturn,
416
          typename... AArgs>
417
struct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {
418
    static_assert(sizeof...(CArgs) == sizeof...(AArgs),
419
                  "pybind11::init(class_factory, alias_factory): class and alias factories "
420
                  "must have identical argument signatures");
421
    static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,
422
                  "pybind11::init(class_factory, alias_factory): class and alias factories "
423
                  "must have identical argument signatures");
424
425
    remove_reference_t<CFunc> class_factory;
426
    remove_reference_t<AFunc> alias_factory;
427
428
    factory(CFunc &&c, AFunc &&a)
429
        : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}
430
431
    // The class factory is called when the `self` type passed to `__init__` is the direct
432
    // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.
433
    template <typename Class, typename... Extra>
434
    void execute(Class &cl, const Extra &...extra) && {
435
        static_assert(Class::has_alias,
436
                      "The two-argument version of `py::init()` can "
437
                      "only be used if the class has an alias");
438
#if defined(__cpp_init_captures) && __cpp_init_captures >= 201304L
439
        cl.def(
440
            "__init__",
441
            [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]
442
#else
443
        auto &class_func = class_factory;
444
        auto &alias_func = alias_factory;
445
        cl.def(
446
            "__init__",
447
            [class_func, alias_func]
448
#endif
449
            (value_and_holder &v_h, CArgs... args) {
450
                if (Py_TYPE(v_h.inst) == v_h.type->type) {
451
                    // If the instance type equals the registered type we don't have inheritance,
452
                    // so don't need the alias and can construct using the class function:
453
                    construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);
454
                } else {
455
                    construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);
456
                }
457
            },
458
            is_new_style_constructor(),
459
            extra...);
460
    }
461
};
462
463
/// Set just the C++ state. Same as `__init__`.
464
template <typename Class, typename T>
465
void setstate(value_and_holder &v_h, T &&result, bool need_alias) {
466
    construct<Class>(v_h, std::forward<T>(result), need_alias);
467
}
468
469
/// Set both the C++ and Python states
470
template <typename Class,
471
          typename T,
472
          typename O,
473
          enable_if_t<std::is_convertible<O, handle>::value, int> = 0>
474
void setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {
475
    construct<Class>(v_h, std::move(result.first), need_alias);
476
    auto d = handle(result.second);
477
    if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {
478
        // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.
479
        // See PR #2972 for details.
480
        return;
481
    }
482
    // Our tests never run into an unset dict, but being careful here for now (see #5658)
483
    auto dict = getattr(reinterpret_cast<PyObject *>(v_h.inst), "__dict__", none());
484
    if (dict.is_none()) {
485
        setattr(reinterpret_cast<PyObject *>(v_h.inst), "__dict__", d);
486
    } else {
487
        // Keep the original object dict and just update it
488
        if (PyDict_Update(dict.ptr(), d.ptr()) < 0) {
489
            throw error_already_set();
490
        }
491
    }
492
}
493
494
/// Implementation for py::pickle(GetState, SetState)
495
template <typename Get,
496
          typename Set,
497
          typename = function_signature_t<Get>,
498
          typename = function_signature_t<Set>>
499
struct pickle_factory;
500
501
template <typename Get,
502
          typename Set,
503
          typename RetState,
504
          typename Self,
505
          typename NewInstance,
506
          typename ArgState>
507
struct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {
508
    using Ret = intrinsic_t<RetState>;
509
    using Arg = intrinsic_t<ArgState>;
510
511
    // Subclasses are now allowed for support between type hint and generic versions of types
512
    // (e.g.) typing::List <--> list
513
    static_assert(std::is_same<Ret, Arg>::value || std::is_base_of<Ret, Arg>::value
514
                      || std::is_base_of<Arg, Ret>::value,
515
                  "The type returned by `__getstate__` must be the same or subclass of the "
516
                  "argument accepted by `__setstate__`");
517
518
    remove_reference_t<Get> get;
519
    remove_reference_t<Set> set;
520
521
    pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}
522
523
    template <typename Class, typename... Extra>
524
    void execute(Class &cl, const Extra &...extra) && {
525
        cl.def("__getstate__", std::move(get), pos_only());
526
527
#if defined(__cpp_init_captures) && __cpp_init_captures >= 201304L
528
        cl.def(
529
            "__setstate__",
530
            [func = std::move(set)]
531
#else
532
        auto &func = set;
533
        cl.def(
534
            "__setstate__",
535
            [func]
536
#endif
537
            (value_and_holder &v_h, ArgState state) {
538
                setstate<Class>(
539
                    v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);
540
            },
541
            is_new_style_constructor(),
542
            extra...);
543
    }
544
};
545
546
PYBIND11_NAMESPACE_END(initimpl)
547
PYBIND11_NAMESPACE_END(detail)
548
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)