Skip to content

Fix multiple inheritance with static properties #679

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ set(PYBIND11_HEADERS
include/pybind11/attr.h
include/pybind11/cast.h
include/pybind11/chrono.h
include/pybind11/class_support.h
include/pybind11/common.h
include/pybind11/complex.h
include/pybind11/descr.h
Expand Down
21 changes: 6 additions & 15 deletions docs/advanced/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,24 +437,15 @@ The section on :ref:`properties` discussed the creation of instance properties
that are implemented in terms of C++ getters and setters.

Static properties can also be created in a similar way to expose getters and
setters of static class attributes. Two things are important to note:

1. Static properties are implemented by instrumenting the *metaclass* of the
class in question -- however, this requires the class to have a modifiable
metaclass in the first place. pybind11 provides a ``py::metaclass()``
annotation that must be specified in the ``class_`` constructor, or any
later method calls to ``def_{property_,∅}_{readwrite,readonly}_static`` will
fail (see the example below).

2. For static properties defined in terms of setter and getter functions, note
that the implicit ``self`` argument also exists in this case and is used to
pass the Python ``type`` subclass instance. This parameter will often not be
needed by the C++ side, and the following example illustrates how to
instantiate a lambda getter function that ignores it:
setters of static class attributes. Note that the implicit ``self`` argument
also exists in this case and is used to pass the Python ``type`` subclass
instance. This parameter will often not be needed by the C++ side, and the
following example illustrates how to instantiate a lambda getter function
that ignores it:

.. code-block:: cpp

py::class_<Foo>(m, "Foo", py::metaclass())
py::class_<Foo>(m, "Foo")
.def_property_readonly_static("foo", [](py::object /* self */) { return Foo(); });

Operator overloading
Expand Down
21 changes: 14 additions & 7 deletions include/pybind11/attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@ struct dynamic_attr { };
struct buffer_protocol { };

/// Annotation which requests that a special metaclass is created for a type
struct metaclass { };
struct metaclass {
handle value;

PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.")
metaclass() = default;

/// Override pybind11's default metaclass
explicit metaclass(handle value) : value(value) { }
};

/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
Expand Down Expand Up @@ -149,8 +157,7 @@ struct function_record {
/// Special data structure which (temporarily) holds metadata about a bound class
struct type_record {
PYBIND11_NOINLINE type_record()
: multiple_inheritance(false), dynamic_attr(false),
buffer_protocol(false), metaclass(false) { }
: multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false) { }

/// Handle to the parent scope
handle scope;
Expand Down Expand Up @@ -179,6 +186,9 @@ struct type_record {
/// Optional docstring
const char *doc = nullptr;

/// Custom metaclass (optional)
handle metaclass;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose adding

    /// Custom metaclass (optional)
    handle metaclass;

below the doc member

/// Multiple inheritance marker
bool multiple_inheritance : 1;

Expand All @@ -188,9 +198,6 @@ struct type_record {
/// Does the class implement the buffer protocol?
bool buffer_protocol : 1;

/// Does the class require its own metaclass?
bool metaclass : 1;

/// Is the default (unique_ptr) holder type used?
bool default_holder : 1;

Expand Down Expand Up @@ -356,7 +363,7 @@ struct process_attribute<buffer_protocol> : process_attribute_default<buffer_pro

template <>
struct process_attribute<metaclass> : process_attribute_default<metaclass> {
static void init(const metaclass &, type_record *r) { r->metaclass = true; }
static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }
};


Expand Down
5 changes: 5 additions & 0 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@

NAMESPACE_BEGIN(pybind11)
NAMESPACE_BEGIN(detail)
inline PyTypeObject *make_static_property_type();
inline PyTypeObject *make_default_metaclass();

/// Additional type information which does not fit into the PyTypeObject
struct type_info {
PyTypeObject *type;
size_t type_size;
void (*init_holder)(PyObject *, const void *);
void (*dealloc)(PyObject *);
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
Expand Down Expand Up @@ -73,6 +76,8 @@ PYBIND11_NOINLINE inline internals &get_internals() {
}
}
);
internals_ptr->static_property_type = make_static_property_type();
internals_ptr->default_metaclass = make_default_metaclass();
}
return *internals_ptr;
}
Expand Down
Loading