support for brace initialization

This commit is contained in:
Wenzel Jakob 2017-08-21 22:48:28 +02:00
parent fb276c661f
commit 4336a7da4a
4 changed files with 47 additions and 5 deletions

View File

@ -492,6 +492,30 @@ you could equivalently write:
which will invoke the constructor in-place at the pre-allocated memory.
Brace initialization
--------------------
``pybind11::init<>`` internally uses C++11 brace initialization to call the
constructor of the target class. This means that it can be used to bind
*implicit* constructors as well:
.. code-block:: cpp
struct Aggregate {
int a;
std::string b;
};
py::class_<Aggregate>(m, "Aggregate")
.def(py::init<int, const std::string &>());
.. note::
Note that brace initialization preferentially invokes constructor overloads
taking a ``std::initializer_list``. In the rare event that this causes an
issue, you can work around it by using ``py::init(...)`` with a lambda
function that constructs the new object as desired.
.. _classes_with_non_public_destructors:
Non-public destructors

View File

@ -172,7 +172,7 @@ template <typename... Args> struct constructor {
// we really can't support that in C++, so just ignore the second __init__.
if (v_h.instance_registered()) return;
construct<Class>(v_h, new Cpp<Class>(std::forward<Args>(args)...), false);
construct<Class>(v_h, new Cpp<Class>{std::forward<Args>(args)...}, false);
}, extra...);
}
@ -186,9 +186,9 @@ template <typename... Args> struct constructor {
if (v_h.instance_registered()) return; // Ignore duplicate __init__ calls (see above)
if (Py_TYPE(v_h.inst) == cl_type->type)
construct<Class>(v_h, new Cpp<Class>(std::forward<Args>(args)...), false);
construct<Class>(v_h, new Cpp<Class>{std::forward<Args>(args)...}, false);
else
construct<Class>(v_h, new Alias<Class>(std::forward<Args>(args)...), true);
construct<Class>(v_h, new Alias<Class>{std::forward<Args>(args)...}, true);
}, extra...);
}
@ -200,7 +200,7 @@ template <typename... Args> struct constructor {
cl.def("__init__", [cl_type](handle self_, Args... args) {
auto v_h = load_v_h(self_, cl_type);
if (v_h.instance_registered()) return; // Ignore duplicate __init__ calls (see above)
construct<Class>(v_h, new Alias<Class>(std::forward<Args>(args)...), true);
construct<Class>(v_h, new Alias<Class>{std::forward<Args>(args)...}, true);
}, extra...);
}
};
@ -214,7 +214,7 @@ template <typename... Args> struct alias_constructor {
cl.def("__init__", [cl_type](handle self_, Args... args) {
auto v_h = load_v_h(self_, cl_type);
if (v_h.instance_registered()) return; // Ignore duplicate __init__ calls (see above)
construct<Class>(v_h, new Alias<Class>(std::forward<Args>(args)...), true);
construct<Class>(v_h, new Alias<Class>{std::forward<Args>(args)...}, true);
}, extra...);
}
};

View File

@ -280,6 +280,17 @@ TEST_SUBMODULE(class_, m) {
#else
.def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo));
#endif
// test_brace_initialization
struct BraceInitialization {
int field1;
std::string field2;
};
py::class_<BraceInitialization>(m, "BraceInitialization")
.def(py::init<int, const std::string &>())
.def_readwrite("field1", &BraceInitialization::field1)
.def_readwrite("field2", &BraceInitialization::field2);
}
template <int N> class BreaksBase { public: virtual ~BreaksBase() = default; };

View File

@ -195,3 +195,10 @@ def test_bind_protected_functions():
c = C()
assert c.foo() == 0
def test_brace_initialization():
""" Tests that simple POD classes can be constructed using C++11 brace initialization """
a = m.BraceInitialization(123, "test")
assert a.field1 == 123
assert a.field2 == "test"