support for brace initialization
diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst
index 4550d0b..8926fa9 100644
--- a/docs/advanced/classes.rst
+++ b/docs/advanced/classes.rst
@@ -492,6 +492,30 @@
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
diff --git a/include/pybind11/detail/init.h b/include/pybind11/detail/init.h
index e98adbb..647279c 100644
--- a/include/pybind11/detail/init.h
+++ b/include/pybind11/detail/init.h
@@ -172,7 +172,7 @@
// 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 @@
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 @@
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 @@
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...);
}
};
diff --git a/tests/test_class.cpp b/tests/test_class.cpp
index af7b0bf..842991a 100644
--- a/tests/test_class.cpp
+++ b/tests/test_class.cpp
@@ -280,6 +280,17 @@
#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; };
diff --git a/tests/test_class.py b/tests/test_class.py
index c8ff857..b2cc275 100644
--- a/tests/test_class.py
+++ b/tests/test_class.py
@@ -195,3 +195,10 @@
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"