mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Fail to compile with MI via class_ ctor parameters
We can't support this for classes from imported modules (which is the primary purpose of a ctor argument base class) because we *have* to have both parent and derived to properly extract a multiple-inheritance base class pointer from a derived class pointer. We could support this for actual `class_<Base, ...> instances, but since in that case the `Base` is already present in the code, it seems more consistent to simply always require MI to go via template options.
This commit is contained in:
parent
d51acb6873
commit
b961626c0c
@ -333,7 +333,7 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
||||
}
|
||||
};
|
||||
|
||||
/// Process a parent class attribute
|
||||
/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees that)
|
||||
template <typename T>
|
||||
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
|
||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||
|
@ -885,11 +885,21 @@ public:
|
||||
|
||||
template <typename... Extra>
|
||||
class_(handle scope, const char *name, const Extra &... extra) {
|
||||
detail::type_record record;
|
||||
using namespace detail;
|
||||
|
||||
// MI can only be specified via class_ template options, not constructor parameters
|
||||
static_assert(
|
||||
none_of<is_pyobject<Extra>...>::value || // no base class arguments, or:
|
||||
( constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base
|
||||
constexpr_sum(is_base<options>::value...) == 0 && // no template option bases
|
||||
none_of<std::is_same<multiple_inheritance, Extra>...>::value), // no multiple_inheritance attr
|
||||
"Error: multiple inheritance bases must be specified via class_ template options");
|
||||
|
||||
type_record record;
|
||||
record.scope = scope;
|
||||
record.name = name;
|
||||
record.type = &typeid(type);
|
||||
record.type_size = sizeof(detail::conditional_t<has_alias, type_alias, type>);
|
||||
record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);
|
||||
record.instance_size = sizeof(instance_type);
|
||||
record.init_holder = init_holder;
|
||||
record.dealloc = dealloc;
|
||||
@ -900,12 +910,12 @@ public:
|
||||
(void) unused;
|
||||
|
||||
/* Process optional arguments, if any */
|
||||
detail::process_attributes<Extra...>::init(extra..., &record);
|
||||
process_attributes<Extra...>::init(extra..., &record);
|
||||
|
||||
detail::generic_type::initialize(record);
|
||||
generic_type::initialize(record);
|
||||
|
||||
if (has_alias) {
|
||||
auto &instances = pybind11::detail::get_internals().registered_types_cpp;
|
||||
auto &instances = get_internals().registered_types_cpp;
|
||||
instances[std::type_index(typeid(type_alias))] = instances[std::type_index(typeid(type))];
|
||||
}
|
||||
}
|
||||
|
@ -31,18 +31,27 @@ struct MIType : Base12 {
|
||||
};
|
||||
|
||||
test_initializer multiple_inheritance([](py::module &m) {
|
||||
py::class_<Base1>(m, "Base1")
|
||||
.def(py::init<int>())
|
||||
.def("foo", &Base1::foo);
|
||||
py::class_<Base1> b1(m, "Base1");
|
||||
b1.def(py::init<int>())
|
||||
.def("foo", &Base1::foo);
|
||||
|
||||
py::class_<Base2>(m, "Base2")
|
||||
.def(py::init<int>())
|
||||
.def("bar", &Base2::bar);
|
||||
py::class_<Base2> b2(m, "Base2");
|
||||
b2.def(py::init<int>())
|
||||
.def("bar", &Base2::bar);
|
||||
|
||||
py::class_<Base12, Base1, Base2>(m, "Base12");
|
||||
|
||||
py::class_<MIType, Base12>(m, "MIType")
|
||||
.def(py::init<int, int>());
|
||||
|
||||
// Uncommenting this should result in a compile time failure (MI can only be specified via
|
||||
// template parameters because pybind has to know the types involved; see discussion in #742 for
|
||||
// details).
|
||||
// struct Base12v2 : Base1, Base2 {
|
||||
// Base12v2(int i, int j) : Base1(i), Base2(j) { }
|
||||
// };
|
||||
// py::class_<Base12v2>(m, "Base12v2", b1, b2)
|
||||
// .def(py::init<int, int>());
|
||||
});
|
||||
|
||||
/* Test the case where not all base classes are specified,
|
||||
|
Loading…
Reference in New Issue
Block a user