mirror of
https://github.com/pybind/pybind11.git
synced 2025-02-18 06:30:54 +00:00
Merge pull request #410 from wjakob/mi
WIP: Multiple inheritance support
This commit is contained in:
commit
d922dffec4
@ -45,10 +45,12 @@ pybind11 can map the following core C++ features to Python
|
|||||||
- Arbitrary exception types
|
- Arbitrary exception types
|
||||||
- Enumerations
|
- Enumerations
|
||||||
- Callbacks
|
- Callbacks
|
||||||
|
- Iterators and ranges
|
||||||
- Custom operators
|
- Custom operators
|
||||||
|
- Single and multiple inheritance
|
||||||
- STL data structures
|
- STL data structures
|
||||||
- Iterators and ranges
|
- Iterators and ranges
|
||||||
- Smart pointers with reference counting like `std::shared_ptr`
|
- Smart pointers with reference counting like ``std::shared_ptr``
|
||||||
- Internal references with correct reference counting
|
- Internal references with correct reference counting
|
||||||
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
||||||
|
|
||||||
|
@ -217,6 +217,8 @@ The following interactive session shows how to call them from Python.
|
|||||||
that demonstrates how to work with callbacks and anonymous functions in
|
that demonstrates how to work with callbacks and anonymous functions in
|
||||||
more detail.
|
more detail.
|
||||||
|
|
||||||
|
.. _overriding_virtuals:
|
||||||
|
|
||||||
Overriding virtual functions in Python
|
Overriding virtual functions in Python
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
@ -2151,3 +2153,45 @@ type is explicitly allowed.
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Multiple Inheritance
|
||||||
|
====================
|
||||||
|
|
||||||
|
pybind11 can create bindings for types that derive from multiple base types
|
||||||
|
(aka. *multiple inheritance*). To do so, specify all bases in the template
|
||||||
|
arguments of the ``class_`` declaration:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<MyType, BaseType1, BaseType2, BaseType3>(m, "MyType")
|
||||||
|
...
|
||||||
|
|
||||||
|
The base types can be specified in arbitrary order, and they can even be
|
||||||
|
interspersed with alias types and holder types (discussed earlier in this
|
||||||
|
document)---pybind11 will automatically find out which is which. The only
|
||||||
|
requirement is that the first template argument is the type to be declared.
|
||||||
|
|
||||||
|
There are two caveats regarding the implementation of this feature:
|
||||||
|
|
||||||
|
1. When only one base type is specified for a C++ type that actually has
|
||||||
|
multiple bases, pybind11 will assume that it does not participate in
|
||||||
|
multiple inheritance, which can lead to undefined behavior. In such cases,
|
||||||
|
add the tag ``multiple_inheritance``:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
py::class_<MyType, BaseType2>(m, "MyType", py::multiple_inheritance());
|
||||||
|
|
||||||
|
The tag is redundant and does not need to be specified when multiple base
|
||||||
|
types are listed.
|
||||||
|
|
||||||
|
2. As was previously discussed in the section on :ref:`overriding_virtuals`, it
|
||||||
|
is easy to create Python types that derive from C++ classes. It is even
|
||||||
|
possible to make use of multiple inheritance to declare a Python class which
|
||||||
|
has e.g. a C++ and a Python class as bases. However, any attempt to create a
|
||||||
|
type that has *two or more* C++ classes in its hierarchy of base types will
|
||||||
|
fail with a fatal error message: ``TypeError: multiple bases have instance
|
||||||
|
lay-out conflict``. Core Python types that are implemented in C (e.g.
|
||||||
|
``dict``, ``list``, ``Exception``, etc.) also fall under this combination
|
||||||
|
and cannot be combined with C++ types bound using pybind11 via multiple
|
||||||
|
inheritance.
|
||||||
|
@ -185,10 +185,9 @@ inheritance relationship:
|
|||||||
std::string bark() const { return "woof!"; }
|
std::string bark() const { return "woof!"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
There are three different ways of indicating a hierarchical relationship to
|
There are two different ways of indicating a hierarchical relationship to
|
||||||
pybind11: the first specifies the C++ base class as an extra template
|
pybind11: the first specifies the C++ base class as an extra template
|
||||||
parameter of the :class:`class_`; the second uses a special ``base`` attribute
|
parameter of the :class:`class_`:
|
||||||
passed into the constructor:
|
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
@ -201,11 +200,6 @@ passed into the constructor:
|
|||||||
.def(py::init<const std::string &>())
|
.def(py::init<const std::string &>())
|
||||||
.def("bark", &Dog::bark);
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
// Method 2: py::base attribute:
|
|
||||||
py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
|
|
||||||
.def(py::init<const std::string &>())
|
|
||||||
.def("bark", &Dog::bark);
|
|
||||||
|
|
||||||
Alternatively, we can also assign a name to the previously bound ``Pet``
|
Alternatively, we can also assign a name to the previously bound ``Pet``
|
||||||
:class:`class_` object and reference it when binding the ``Dog`` class:
|
:class:`class_` object and reference it when binding the ``Dog`` class:
|
||||||
|
|
||||||
@ -215,13 +209,13 @@ Alternatively, we can also assign a name to the previously bound ``Pet``
|
|||||||
pet.def(py::init<const std::string &>())
|
pet.def(py::init<const std::string &>())
|
||||||
.def_readwrite("name", &Pet::name);
|
.def_readwrite("name", &Pet::name);
|
||||||
|
|
||||||
// Method 3: pass parent class_ object:
|
// Method 2: pass parent class_ object:
|
||||||
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
|
py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
|
||||||
.def(py::init<const std::string &>())
|
.def(py::init<const std::string &>())
|
||||||
.def("bark", &Dog::bark);
|
.def("bark", &Dog::bark);
|
||||||
|
|
||||||
Functionality-wise, all three approaches are completely equivalent. Afterwards,
|
Functionality-wise, both approaches are equivalent. Afterwards, instances will
|
||||||
instances will expose fields and methods of both types:
|
expose fields and methods of both types:
|
||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
|
||||||
|
@ -35,12 +35,14 @@ The following core C++ features can be mapped to Python
|
|||||||
- Instance methods and static methods
|
- Instance methods and static methods
|
||||||
- Overloaded functions
|
- Overloaded functions
|
||||||
- Instance attributes and static attributes
|
- Instance attributes and static attributes
|
||||||
- Exceptions
|
- Arbitrary exception types
|
||||||
- Enumerations
|
- Enumerations
|
||||||
- Iterators and ranges
|
|
||||||
- Callbacks
|
- Callbacks
|
||||||
|
- Iterators and ranges
|
||||||
- Custom operators
|
- Custom operators
|
||||||
|
- Single and multiple inheritance
|
||||||
- STL data structures
|
- STL data structures
|
||||||
|
- Iterators and ranges
|
||||||
- Smart pointers with reference counting like ``std::shared_ptr``
|
- Smart pointers with reference counting like ``std::shared_ptr``
|
||||||
- Internal references with correct reference counting
|
- Internal references with correct reference counting
|
||||||
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
- C++ classes with virtual (and pure virtual) methods can be extended in Python
|
||||||
|
@ -9,15 +9,12 @@ certain limitations:
|
|||||||
values. This means that some additional care is needed to avoid bugs that
|
values. This means that some additional care is needed to avoid bugs that
|
||||||
would be caught by the type checker in a traditional C++ program.
|
would be caught by the type checker in a traditional C++ program.
|
||||||
|
|
||||||
- Multiple inheritance relationships on the C++ side cannot be mapped to
|
|
||||||
Python.
|
|
||||||
|
|
||||||
- The NumPy interface ``pybind11::array`` greatly simplifies accessing
|
- The NumPy interface ``pybind11::array`` greatly simplifies accessing
|
||||||
numerical data from C++ (and vice versa), but it's not a full-blown array
|
numerical data from C++ (and vice versa), but it's not a full-blown array
|
||||||
class like ``Eigen::Array`` or ``boost.multi_array``.
|
class like ``Eigen::Array`` or ``boost.multi_array``.
|
||||||
|
|
||||||
All of these features could be implemented but would lead to a significant
|
These features could be implemented but would lead to a significant increase in
|
||||||
increase in complexity. I've decided to draw the line here to keep this project
|
complexity. I've decided to draw the line here to keep this project simple and
|
||||||
simple and compact. Users who absolutely require these features are encouraged
|
compact. Users who absolutely require these features are encouraged to fork
|
||||||
to fork pybind11.
|
pybind11.
|
||||||
|
|
||||||
|
@ -33,11 +33,17 @@ struct name { const char *value; name(const char *value) : value(value) { } };
|
|||||||
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
struct sibling { handle value; sibling(const handle &value) : value(value.ptr()) { } };
|
||||||
|
|
||||||
/// Annotation indicating that a class derives from another given type
|
/// Annotation indicating that a class derives from another given type
|
||||||
template <typename T> struct base { };
|
template <typename T> struct base {
|
||||||
|
PYBIND11_DEPRECATED("base<T>() was deprecated in favor of specifying 'T' as a template argument to class_")
|
||||||
|
base() { }
|
||||||
|
};
|
||||||
|
|
||||||
/// Keep patient alive while nurse lives
|
/// Keep patient alive while nurse lives
|
||||||
template <int Nurse, int Patient> struct keep_alive { };
|
template <int Nurse, int Patient> struct keep_alive { };
|
||||||
|
|
||||||
|
/// Annotation indicating that a class is involved in a multiple inheritance relationship
|
||||||
|
struct multiple_inheritance { };
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
enum op_id : int;
|
enum op_id : int;
|
||||||
@ -124,6 +130,8 @@ struct function_record {
|
|||||||
|
|
||||||
/// Special data structure which (temporarily) holds metadata about a bound class
|
/// Special data structure which (temporarily) holds metadata about a bound class
|
||||||
struct type_record {
|
struct type_record {
|
||||||
|
PYBIND11_NOINLINE type_record() { }
|
||||||
|
|
||||||
/// Handle to the parent scope
|
/// Handle to the parent scope
|
||||||
handle scope;
|
handle scope;
|
||||||
|
|
||||||
@ -145,21 +153,36 @@ struct type_record {
|
|||||||
/// Function pointer to class_<..>::dealloc
|
/// Function pointer to class_<..>::dealloc
|
||||||
void (*dealloc)(PyObject *) = nullptr;
|
void (*dealloc)(PyObject *) = nullptr;
|
||||||
|
|
||||||
// Pointer to RTTI type_info data structure of base class
|
/// List of base classes of the newly created type
|
||||||
const std::type_info *base_type = nullptr;
|
list bases;
|
||||||
|
|
||||||
/// OR: Python handle to base class
|
|
||||||
handle base_handle;
|
|
||||||
|
|
||||||
/// Optional docstring
|
/// Optional docstring
|
||||||
const char *doc = nullptr;
|
const char *doc = nullptr;
|
||||||
|
|
||||||
|
/// Multiple inheritance marker
|
||||||
|
bool multiple_inheritance = false;
|
||||||
|
|
||||||
|
PYBIND11_NOINLINE void add_base(const std::type_info *base, void *(*caster)(void *)) {
|
||||||
|
auto base_info = detail::get_type_info(*base, false);
|
||||||
|
if (!base_info) {
|
||||||
|
std::string tname(base->name());
|
||||||
|
detail::clean_type_id(tname);
|
||||||
|
pybind11_fail("generic_type: type \"" + std::string(name) +
|
||||||
|
"\" referenced unknown base type \"" + tname + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
bases.append((PyObject *) base_info->type);
|
||||||
|
|
||||||
|
if (caster)
|
||||||
|
base_info->implicit_casts.push_back(std::make_pair(type, caster));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Partial template specializations to process custom attributes provided to
|
* Partial template specializations to process custom attributes provided to
|
||||||
* cpp_function_ and class_. These are either used to initialize the respective
|
* cpp_function_ and class_. These are either used to initialize the respective
|
||||||
* fields in the type_record and function_record data structures or executed
|
* fields in the type_record and function_record data structures or executed at
|
||||||
* at runtime to deal with custom call policies (e.g. keep_alive).
|
* runtime to deal with custom call policies (e.g. keep_alive).
|
||||||
*/
|
*/
|
||||||
template <typename T, typename SFINAE = void> struct process_attribute;
|
template <typename T, typename SFINAE = void> struct process_attribute;
|
||||||
|
|
||||||
@ -253,14 +276,20 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|||||||
|
|
||||||
/// Process a parent class attribute
|
/// Process a parent class attribute
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct process_attribute<T, typename std::enable_if<std::is_base_of<handle, T>::value>::type> : process_attribute_default<handle> {
|
struct process_attribute<T, enable_if_t<std::is_base_of<handle, T>::value>> : process_attribute_default<handle> {
|
||||||
static void init(const handle &h, type_record *r) { r->base_handle = h; }
|
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Process a parent class attribute
|
/// Process a parent class attribute (deprecated, does not support multiple inheritance)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
||||||
static void init(const base<T> &, type_record *r) { r->base_type = &typeid(T); }
|
static void init(const base<T> &, type_record *r) { r->add_base(&typeid(T), nullptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process a multiple inheritance attribute
|
||||||
|
template <>
|
||||||
|
struct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {
|
||||||
|
static void init(const multiple_inheritance &, type_record *r) { r->multiple_inheritance = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/***
|
/***
|
||||||
@ -269,13 +298,13 @@ struct process_attribute<base<T>> : process_attribute_default<base<T>> {
|
|||||||
* otherwise
|
* otherwise
|
||||||
*/
|
*/
|
||||||
template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
|
template <int Nurse, int Patient> struct process_attribute<keep_alive<Nurse, Patient>> : public process_attribute_default<keep_alive<Nurse, Patient>> {
|
||||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
|
template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
|
static void precall(handle args) { keep_alive_impl(Nurse, Patient, args, handle()); }
|
||||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N != 0 && P != 0, int>::type = 0>
|
template <int N = Nurse, int P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>
|
||||||
static void postcall(handle, handle) { }
|
static void postcall(handle, handle) { }
|
||||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
|
template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
static void precall(handle) { }
|
static void precall(handle) { }
|
||||||
template <int N = Nurse, int P = Patient, typename std::enable_if<N == 0 || P == 0, int>::type = 0>
|
template <int N = Nurse, int P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>
|
||||||
static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
|
static void postcall(handle args, handle ret) { keep_alive_impl(Nurse, Patient, args, ret); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include "descr.h"
|
#include "descr.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
NAMESPACE_BEGIN(pybind11)
|
NAMESPACE_BEGIN(pybind11)
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
@ -25,9 +24,13 @@ struct type_info {
|
|||||||
PyTypeObject *type;
|
PyTypeObject *type;
|
||||||
size_t type_size;
|
size_t type_size;
|
||||||
void (*init_holder)(PyObject *, const void *);
|
void (*init_holder)(PyObject *, const void *);
|
||||||
std::vector<PyObject *(*)(PyObject *, PyTypeObject *) > implicit_conversions;
|
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
|
||||||
|
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
|
||||||
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;
|
||||||
void *get_buffer_data = nullptr;
|
void *get_buffer_data = nullptr;
|
||||||
|
/** A simple type never occurs as a (direct or indirect) parent
|
||||||
|
* of a class that makes use of multiple inheritance */
|
||||||
|
bool simple_type = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline internals &get_internals() {
|
PYBIND11_NOINLINE inline internals &get_internals() {
|
||||||
@ -72,32 +75,34 @@ PYBIND11_NOINLINE inline internals &get_internals() {
|
|||||||
return *internals_ptr;
|
return *internals_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type, bool throw_if_missing = true) {
|
PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) {
|
||||||
auto const &type_dict = get_internals().registered_types_py;
|
auto const &type_dict = get_internals().registered_types_py;
|
||||||
do {
|
do {
|
||||||
auto it = type_dict.find(type);
|
auto it = type_dict.find(type);
|
||||||
if (it != type_dict.end())
|
if (it != type_dict.end())
|
||||||
return (detail::type_info *) it->second;
|
return (detail::type_info *) it->second;
|
||||||
type = type->tp_base;
|
type = type->tp_base;
|
||||||
if (!type) {
|
if (!type)
|
||||||
if (throw_if_missing)
|
|
||||||
pybind11_fail("pybind11::detail::get_type_info: unable to find type object!");
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp) {
|
PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp, bool throw_if_missing) {
|
||||||
auto &types = get_internals().registered_types_cpp;
|
auto &types = get_internals().registered_types_cpp;
|
||||||
|
|
||||||
auto it = types.find(std::type_index(tp));
|
auto it = types.find(std::type_index(tp));
|
||||||
if (it != types.end())
|
if (it != types.end())
|
||||||
return (detail::type_info *) it->second;
|
return (detail::type_info *) it->second;
|
||||||
|
if (throw_if_missing) {
|
||||||
|
std::string tname = tp.name();
|
||||||
|
detail::clean_type_id(tname);
|
||||||
|
pybind11_fail("pybind11::detail::get_type_info: unable to find type info for \"" + tname + "\"");
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) {
|
PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {
|
||||||
detail::type_info *type_info = get_type_info(tp);
|
detail::type_info *type_info = get_type_info(tp, throw_if_missing);
|
||||||
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +129,7 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
|
|||||||
auto &instances = get_internals().registered_instances;
|
auto &instances = get_internals().registered_instances;
|
||||||
auto range = instances.equal_range(ptr);
|
auto range = instances.equal_range(ptr);
|
||||||
for (auto it = range.first; it != range.second; ++it) {
|
for (auto it = range.first; it != range.second; ++it) {
|
||||||
auto instance_type = detail::get_type_info(Py_TYPE(it->second), false);
|
auto instance_type = detail::get_type_info(Py_TYPE(it->second));
|
||||||
if (instance_type && instance_type == type)
|
if (instance_type && instance_type == type)
|
||||||
return handle((PyObject *) it->second);
|
return handle((PyObject *) it->second);
|
||||||
}
|
}
|
||||||
@ -149,18 +154,56 @@ inline void keep_alive_impl(handle nurse, handle patient);
|
|||||||
class type_caster_generic {
|
class type_caster_generic {
|
||||||
public:
|
public:
|
||||||
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info)
|
||||||
: typeinfo(get_type_info(type_info)) { }
|
: typeinfo(get_type_info(type_info, false)) { }
|
||||||
|
|
||||||
PYBIND11_NOINLINE bool load(handle src, bool convert) {
|
PYBIND11_NOINLINE bool load(handle src, bool convert) {
|
||||||
|
return load(src, convert, Py_TYPE(src.ptr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(handle src, bool convert, PyTypeObject *tobj) {
|
||||||
if (!src || !typeinfo)
|
if (!src || !typeinfo)
|
||||||
return false;
|
return false;
|
||||||
if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
value = nullptr;
|
value = nullptr;
|
||||||
return true;
|
return true;
|
||||||
} else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
|
|
||||||
value = ((instance<void> *) src.ptr())->value;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */
|
||||||
|
/* Check if we can safely perform a reinterpret-style cast */
|
||||||
|
if (PyType_IsSubtype(tobj, typeinfo->type)) {
|
||||||
|
value = reinterpret_cast<instance<void> *>(src.ptr())->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else { /* Case 2: multiple inheritance */
|
||||||
|
/* Check if we can safely perform a reinterpret-style cast */
|
||||||
|
if (tobj == typeinfo->type) {
|
||||||
|
value = reinterpret_cast<instance<void> *>(src.ptr())->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is a python class, also check the parents recursively */
|
||||||
|
auto const &type_dict = get_internals().registered_types_py;
|
||||||
|
bool new_style_class = PyType_Check(tobj);
|
||||||
|
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
|
||||||
|
tuple parents(tobj->tp_bases, true);
|
||||||
|
for (handle parent : parents) {
|
||||||
|
bool result = load(src, convert, (PyTypeObject *) parent.ptr());
|
||||||
|
if (result)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try implicit casts */
|
||||||
|
for (auto &cast : typeinfo->implicit_casts) {
|
||||||
|
type_caster_generic sub_caster(*cast.first);
|
||||||
|
if (sub_caster.load(src, convert)) {
|
||||||
|
value = cast.second(sub_caster.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform an implicit conversion */
|
||||||
if (convert) {
|
if (convert) {
|
||||||
for (auto &converter : typeinfo->implicit_conversions) {
|
for (auto &converter : typeinfo->implicit_conversions) {
|
||||||
temp = object(converter(src.ptr(), typeinfo->type), false);
|
temp = object(converter(src.ptr(), typeinfo->type), false);
|
||||||
@ -201,7 +244,7 @@ public:
|
|||||||
|
|
||||||
auto it_instances = internals.registered_instances.equal_range(src);
|
auto it_instances = internals.registered_instances.equal_range(src);
|
||||||
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
||||||
auto instance_type = detail::get_type_info(Py_TYPE(it_i->second), false);
|
auto instance_type = detail::get_type_info(Py_TYPE(it_i->second));
|
||||||
if (instance_type && instance_type == tinfo)
|
if (instance_type && instance_type == tinfo)
|
||||||
return handle((PyObject *) it_i->second).inc_ref();
|
return handle((PyObject *) it_i->second).inc_ref();
|
||||||
}
|
}
|
||||||
@ -262,7 +305,8 @@ template <typename type> class type_caster_base : public type_caster_generic {
|
|||||||
public:
|
public:
|
||||||
static PYBIND11_DESCR name() { return type_descr(_<type>()); }
|
static PYBIND11_DESCR name() { return type_descr(_<type>()); }
|
||||||
|
|
||||||
type_caster_base() : type_caster_generic(typeid(type)) { }
|
type_caster_base() : type_caster_base(typeid(type)) { }
|
||||||
|
type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
|
||||||
|
|
||||||
static handle cast(const itype &src, return_value_policy policy, handle parent) {
|
static handle cast(const itype &src, return_value_policy policy, handle parent) {
|
||||||
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
if (policy == return_value_policy::automatic || policy == return_value_policy::automatic_reference)
|
||||||
@ -299,10 +343,10 @@ protected:
|
|||||||
#else
|
#else
|
||||||
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
|
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
|
||||||
Use a workaround that only tests for constructibility for now. */
|
Use a workaround that only tests for constructibility for now. */
|
||||||
template <typename T = type, typename = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
|
template <typename T = type, typename = enable_if_t<std::is_copy_constructible<T>::value>>
|
||||||
static Constructor make_copy_constructor(const T *value) {
|
static Constructor make_copy_constructor(const T *value) {
|
||||||
return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; }
|
return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; }
|
||||||
template <typename T = type, typename = typename std::enable_if<std::is_move_constructible<T>::value>::type>
|
template <typename T = type, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
||||||
static Constructor make_move_constructor(const T *value) {
|
static Constructor make_move_constructor(const T *value) {
|
||||||
return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; }
|
return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; }
|
||||||
#endif
|
#endif
|
||||||
@ -343,8 +387,8 @@ public:
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct type_caster<
|
struct type_caster<
|
||||||
T, typename std::enable_if<std::is_integral<T>::value ||
|
T, enable_if_t<std::is_integral<T>::value ||
|
||||||
std::is_floating_point<T>::value>::type> {
|
std::is_floating_point<T>::value>> {
|
||||||
typedef typename std::conditional<sizeof(T) <= sizeof(long), long, long long>::type _py_type_0;
|
typedef typename std::conditional<sizeof(T) <= sizeof(long), long, long long>::type _py_type_0;
|
||||||
typedef typename std::conditional<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1;
|
typedef typename std::conditional<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1;
|
||||||
typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
|
typedef typename std::conditional<std::is_floating_point<T>::value, double, _py_type_1>::type py_type;
|
||||||
@ -433,7 +477,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if this is a C++ type */
|
/* Check if this is a C++ type */
|
||||||
if (get_type_info((PyTypeObject *) h.get_type().ptr(), false)) {
|
if (get_type_info((PyTypeObject *) h.get_type().ptr())) {
|
||||||
value = ((instance<void> *) h.ptr())->value;
|
value = ((instance<void> *) h.ptr())->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -658,20 +702,20 @@ public:
|
|||||||
return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
return load(src, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = itype, typename std::enable_if<
|
template <typename T = itype, enable_if_t<
|
||||||
!std::is_same<T, args_type>::value &&
|
!std::is_same<T, args_type>::value &&
|
||||||
!std::is_same<T, args_kwargs_type>::value, int>::type = 0>
|
!std::is_same<T, args_kwargs_type>::value, int> = 0>
|
||||||
bool load_args(handle args, handle, bool convert) {
|
bool load_args(handle args, handle, bool convert) {
|
||||||
return load(args, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
return load(args, convert, typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = itype, typename std::enable_if<std::is_same<T, args_type>::value, int>::type = 0>
|
template <typename T = itype, enable_if_t<std::is_same<T, args_type>::value, int> = 0>
|
||||||
bool load_args(handle args, handle, bool convert) {
|
bool load_args(handle args, handle, bool convert) {
|
||||||
std::get<0>(value).load(args, convert);
|
std::get<0>(value).load(args, convert);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = itype, typename std::enable_if<std::is_same<T, args_kwargs_type>::value, int>::type = 0>
|
template <typename T = itype, enable_if_t<std::is_same<T, args_kwargs_type>::value, int> = 0>
|
||||||
bool load_args(handle args, handle kwargs, bool convert) {
|
bool load_args(handle args, handle kwargs, bool convert) {
|
||||||
std::get<0>(value).load(args, convert);
|
std::get<0>(value).load(args, convert);
|
||||||
std::get<1>(value).load(kwargs, convert);
|
std::get<1>(value).load(kwargs, convert);
|
||||||
@ -690,11 +734,11 @@ public:
|
|||||||
return type_descr(_("Tuple[") + element_names() + _("]"));
|
return type_descr(_("Tuple[") + element_names() + _("]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ReturnValue, typename Func> typename std::enable_if<!std::is_void<ReturnValue>::value, ReturnValue>::type call(Func &&f) {
|
template <typename ReturnValue, typename Func> enable_if_t<!std::is_void<ReturnValue>::value, ReturnValue> call(Func &&f) {
|
||||||
return call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
|
return call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ReturnValue, typename Func> typename std::enable_if<std::is_void<ReturnValue>::value, void_type>::type call(Func &&f) {
|
template <typename ReturnValue, typename Func> enable_if_t<std::is_void<ReturnValue>::value, void_type> call(Func &&f) {
|
||||||
call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
|
call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
|
||||||
return void_type();
|
return void_type();
|
||||||
}
|
}
|
||||||
@ -749,22 +793,56 @@ protected:
|
|||||||
/// Type caster for holder types like std::shared_ptr, etc.
|
/// Type caster for holder types like std::shared_ptr, etc.
|
||||||
template <typename type, typename holder_type> class type_caster_holder : public type_caster_base<type> {
|
template <typename type, typename holder_type> class type_caster_holder : public type_caster_base<type> {
|
||||||
public:
|
public:
|
||||||
using type_caster_base<type>::cast;
|
using base = type_caster_base<type>;
|
||||||
using type_caster_base<type>::typeinfo;
|
using base::base;
|
||||||
using type_caster_base<type>::value;
|
using base::cast;
|
||||||
using type_caster_base<type>::temp;
|
using base::typeinfo;
|
||||||
|
using base::value;
|
||||||
|
using base::temp;
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
PYBIND11_NOINLINE bool load(handle src, bool convert) {
|
||||||
if (!src || !typeinfo) {
|
return load(src, convert, Py_TYPE(src.ptr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load(handle src, bool convert, PyTypeObject *tobj) {
|
||||||
|
if (!src || !typeinfo)
|
||||||
return false;
|
return false;
|
||||||
} else if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
value = nullptr;
|
value = nullptr;
|
||||||
return true;
|
return true;
|
||||||
} else if (PyType_IsSubtype(Py_TYPE(src.ptr()), typeinfo->type)) {
|
}
|
||||||
auto inst = (instance<type, holder_type> *) src.ptr();
|
|
||||||
value = (void *) inst->value;
|
if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */
|
||||||
holder = inst->holder;
|
/* Check if we can safely perform a reinterpret-style cast */
|
||||||
return true;
|
if (PyType_IsSubtype(tobj, typeinfo->type)) {
|
||||||
|
auto inst = (instance<type, holder_type> *) src.ptr();
|
||||||
|
value = (void *) inst->value;
|
||||||
|
holder = inst->holder;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else { /* Case 2: multiple inheritance */
|
||||||
|
/* Check if we can safely perform a reinterpret-style cast */
|
||||||
|
if (tobj == typeinfo->type) {
|
||||||
|
auto inst = (instance<type, holder_type> *) src.ptr();
|
||||||
|
value = (void *) inst->value;
|
||||||
|
holder = inst->holder;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is a python class, also check the parents recursively */
|
||||||
|
auto const &type_dict = get_internals().registered_types_py;
|
||||||
|
bool new_style_class = PyType_Check(tobj);
|
||||||
|
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
|
||||||
|
tuple parents(tobj->tp_bases, true);
|
||||||
|
for (handle parent : parents) {
|
||||||
|
bool result = load(src, convert, (PyTypeObject *) parent.ptr());
|
||||||
|
if (result)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_implicit_casts(src, convert))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert) {
|
if (convert) {
|
||||||
@ -774,6 +852,23 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = holder_type, detail::enable_if_t<!std::is_constructible<T, const T &, type*>::value, int> = 0>
|
||||||
|
bool try_implicit_casts(handle, bool) { return false; }
|
||||||
|
|
||||||
|
template <typename T = holder_type, detail::enable_if_t<std::is_constructible<T, const T &, type*>::value, int> = 0>
|
||||||
|
bool try_implicit_casts(handle src, bool convert) {
|
||||||
|
for (auto &cast : typeinfo->implicit_casts) {
|
||||||
|
type_caster_holder sub_caster(*cast.first);
|
||||||
|
if (sub_caster.load(src, convert)) {
|
||||||
|
value = cast.second(sub_caster.value);
|
||||||
|
holder = holder_type(sub_caster.holder, (type *) value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,12 +908,12 @@ template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { retur
|
|||||||
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
|
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
struct type_caster<type, typename std::enable_if<std::is_base_of<handle, type>::value>::type> {
|
struct type_caster<type, enable_if_t<std::is_base_of<handle, type>::value>> {
|
||||||
public:
|
public:
|
||||||
template <typename T = type, typename std::enable_if<!std::is_base_of<object, T>::value, int>::type = 0>
|
template <typename T = type, enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
|
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
|
||||||
|
|
||||||
template <typename T = type, typename std::enable_if<std::is_base_of<object, T>::value, int>::type = 0>
|
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); }
|
bool load(handle src, bool /* convert */) { value = type(src, true); return value.check(); }
|
||||||
|
|
||||||
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
@ -837,21 +932,21 @@ public:
|
|||||||
// must have ref_count() == 1)h
|
// must have ref_count() == 1)h
|
||||||
// If any of the above are not satisfied, we fall back to copying.
|
// If any of the above are not satisfied, we fall back to copying.
|
||||||
template <typename T, typename SFINAE = void> struct move_is_plain_type : std::false_type {};
|
template <typename T, typename SFINAE = void> struct move_is_plain_type : std::false_type {};
|
||||||
template <typename T> struct move_is_plain_type<T, typename std::enable_if<
|
template <typename T> struct move_is_plain_type<T, enable_if_t<
|
||||||
!std::is_void<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value && !std::is_const<T>::value
|
!std::is_void<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value && !std::is_const<T>::value
|
||||||
>::type> : std::true_type {};
|
>> : std::true_type { };
|
||||||
template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
|
template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
|
||||||
template <typename T> struct move_always<T, typename std::enable_if<
|
template <typename T> struct move_always<T, enable_if_t<
|
||||||
move_is_plain_type<T>::value &&
|
move_is_plain_type<T>::value &&
|
||||||
!std::is_copy_constructible<T>::value && std::is_move_constructible<T>::value &&
|
!std::is_copy_constructible<T>::value && std::is_move_constructible<T>::value &&
|
||||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
||||||
>::type> : std::true_type {};
|
>> : std::true_type { };
|
||||||
template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
|
template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
|
||||||
template <typename T> struct move_if_unreferenced<T, typename std::enable_if<
|
template <typename T> struct move_if_unreferenced<T, enable_if_t<
|
||||||
move_is_plain_type<T>::value &&
|
move_is_plain_type<T>::value &&
|
||||||
!move_always<T>::value && std::is_move_constructible<T>::value &&
|
!move_always<T>::value && std::is_move_constructible<T>::value &&
|
||||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
||||||
>::type> : std::true_type {};
|
>> : std::true_type { };
|
||||||
template <typename T> using move_never = std::integral_constant<bool, !move_always<T>::value && !move_if_unreferenced<T>::value>;
|
template <typename T> using move_never = std::integral_constant<bool, !move_always<T>::value && !move_if_unreferenced<T>::value>;
|
||||||
|
|
||||||
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
|
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
|
||||||
@ -968,7 +1063,6 @@ template <> inline void cast_safe<void>(object &&) {}
|
|||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
|
|
||||||
template <return_value_policy policy = return_value_policy::automatic_reference,
|
template <return_value_policy policy = return_value_policy::automatic_reference,
|
||||||
typename... Args> tuple make_tuple(Args&&... args_) {
|
typename... Args> tuple make_tuple(Args&&... args_) {
|
||||||
const size_t size = sizeof...(Args);
|
const size_t size = sizeof...(Args);
|
||||||
@ -1023,7 +1117,7 @@ struct arg_v : arg {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; }
|
arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; }
|
||||||
|
|
||||||
/// Alias for backward compatibility -- to be remove in version 2.0
|
/// Alias for backward compatibility -- to be removed in version 2.0
|
||||||
template <typename /*unused*/> using arg_t = arg_v;
|
template <typename /*unused*/> using arg_t = arg_v;
|
||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
@ -1199,7 +1293,7 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
|
|||||||
"Invalid function call: positional args must precede keywords and ** unpacking; "
|
"Invalid function call: positional args must precede keywords and ** unpacking; "
|
||||||
"* unpacking must precede ** unpacking"
|
"* unpacking must precede ** unpacking"
|
||||||
);
|
);
|
||||||
return {std::forward<Args>(args)...};
|
return { std::forward<Args>(args)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
@ -30,6 +30,16 @@
|
|||||||
# define PYBIND11_NOINLINE __attribute__ ((noinline))
|
# define PYBIND11_NOINLINE __attribute__ ((noinline))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus > 201103L
|
||||||
|
# define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]]
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason)))
|
||||||
|
#elif defined(__GNUG__)
|
||||||
|
# define PYBIND11_DEPRECATED(reason) __attribute__((deprecated))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define PYBIND11_DEPRECATED(reason) __declspec(deprecated)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PYBIND11_VERSION_MAJOR 1
|
#define PYBIND11_VERSION_MAJOR 1
|
||||||
#define PYBIND11_VERSION_MINOR 9
|
#define PYBIND11_VERSION_MINOR 9
|
||||||
#define PYBIND11_VERSION_PATCH dev0
|
#define PYBIND11_VERSION_PATCH dev0
|
||||||
@ -79,6 +89,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
|
||||||
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
|
||||||
@ -431,14 +442,14 @@ PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used in
|
|||||||
|
|
||||||
template <typename T, typename SFINAE = void> struct format_descriptor { };
|
template <typename T, typename SFINAE = void> struct format_descriptor { };
|
||||||
|
|
||||||
template <typename T> struct format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> {
|
template <typename T> struct format_descriptor<T, detail::enable_if_t<std::is_integral<T>::value>> {
|
||||||
static constexpr const char value[2] =
|
static constexpr const char value[2] =
|
||||||
{ "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned<T>::value ? 1 : 0)], '\0' };
|
{ "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned<T>::value ? 1 : 0)], '\0' };
|
||||||
static std::string format() { return value; }
|
static std::string format() { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> constexpr const char format_descriptor<
|
template <typename T> constexpr const char format_descriptor<
|
||||||
T, typename std::enable_if<std::is_integral<T>::value>::type>::value[2];
|
T, detail::enable_if_t<std::is_integral<T>::value>>::value[2];
|
||||||
|
|
||||||
/// RAII wrapper that temporarily clears any Python error state
|
/// RAII wrapper that temporarily clears any Python error state
|
||||||
struct error_scope {
|
struct error_scope {
|
||||||
|
@ -86,11 +86,11 @@ template <size_t...Digits> struct int_to_str<0, Digits...> {
|
|||||||
|
|
||||||
// Ternary description (like std::conditional)
|
// Ternary description (like std::conditional)
|
||||||
template <bool B, size_t Size1, size_t Size2>
|
template <bool B, size_t Size1, size_t Size2>
|
||||||
constexpr typename std::enable_if<B, descr<Size1 - 1, 0>>::type _(char const(&text1)[Size1], char const(&)[Size2]) {
|
constexpr enable_if_t<B, descr<Size1 - 1, 0>> _(char const(&text1)[Size1], char const(&)[Size2]) {
|
||||||
return _(text1);
|
return _(text1);
|
||||||
}
|
}
|
||||||
template <bool B, size_t Size1, size_t Size2>
|
template <bool B, size_t Size1, size_t Size2>
|
||||||
constexpr typename std::enable_if<!B, descr<Size2 - 1, 0>>::type _(char const(&)[Size1], char const(&text2)[Size2]) {
|
constexpr enable_if_t<!B, descr<Size2 - 1, 0>> _(char const(&)[Size1], char const(&text2)[Size2]) {
|
||||||
return _(text2);
|
return _(text2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,8 +164,8 @@ PYBIND11_NOINLINE inline descr _(const char *text) {
|
|||||||
return descr(text, types);
|
return descr(text, types);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool B> PYBIND11_NOINLINE typename std::enable_if<B, descr>::type _(const char *text1, const char *) { return _(text1); }
|
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
|
||||||
template <bool B> PYBIND11_NOINLINE typename std::enable_if<!B, descr>::type _(char const *, const char *text2) { return _(text2); }
|
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
|
||||||
|
|
||||||
template <typename Type> PYBIND11_NOINLINE descr _() {
|
template <typename Type> PYBIND11_NOINLINE descr _() {
|
||||||
const std::type_info *types[2] = { &typeid(Type), nullptr };
|
const std::type_info *types[2] = { &typeid(Type), nullptr };
|
||||||
|
@ -46,9 +46,9 @@ public:
|
|||||||
// type_caster to handle argument copying/forwarding.
|
// type_caster to handle argument copying/forwarding.
|
||||||
template <typename T> class is_eigen_ref {
|
template <typename T> class is_eigen_ref {
|
||||||
private:
|
private:
|
||||||
template<typename Derived> static typename std::enable_if<
|
template<typename Derived> static enable_if_t<
|
||||||
std::is_same<typename std::remove_const<T>::type, Eigen::Ref<Derived>>::value,
|
std::is_same<typename std::remove_const<T>::type, Eigen::Ref<Derived>>::value,
|
||||||
Derived>::type test(const Eigen::Ref<Derived> &);
|
Derived> test(const Eigen::Ref<Derived> &);
|
||||||
static void test(...);
|
static void test(...);
|
||||||
public:
|
public:
|
||||||
typedef decltype(test(std::declval<T>())) Derived;
|
typedef decltype(test(std::declval<T>())) Derived;
|
||||||
@ -77,7 +77,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value && !is_eigen_ref<Type>::value>::type> {
|
struct type_caster<Type, enable_if_t<is_eigen_dense<Type>::value && !is_eigen_ref<Type>::value>> {
|
||||||
typedef typename Type::Scalar Scalar;
|
typedef typename Type::Scalar Scalar;
|
||||||
static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
|
static constexpr bool rowMajor = Type::Flags & Eigen::RowMajorBit;
|
||||||
static constexpr bool isVector = Type::IsVectorAtCompileTime;
|
static constexpr bool isVector = Type::IsVectorAtCompileTime;
|
||||||
@ -149,18 +149,18 @@ struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value &&
|
|||||||
_("[") + rows() + _(", ") + cols() + _("]]"));
|
_("[") + rows() + _(", ") + cols() + _("]]"));
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename T = Type, typename std::enable_if<T::RowsAtCompileTime == Eigen::Dynamic, int>::type = 0>
|
template <typename T = Type, enable_if_t<T::RowsAtCompileTime == Eigen::Dynamic, int> = 0>
|
||||||
static PYBIND11_DESCR rows() { return _("m"); }
|
static PYBIND11_DESCR rows() { return _("m"); }
|
||||||
template <typename T = Type, typename std::enable_if<T::RowsAtCompileTime != Eigen::Dynamic, int>::type = 0>
|
template <typename T = Type, enable_if_t<T::RowsAtCompileTime != Eigen::Dynamic, int> = 0>
|
||||||
static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); }
|
static PYBIND11_DESCR rows() { return _<T::RowsAtCompileTime>(); }
|
||||||
template <typename T = Type, typename std::enable_if<T::ColsAtCompileTime == Eigen::Dynamic, int>::type = 0>
|
template <typename T = Type, enable_if_t<T::ColsAtCompileTime == Eigen::Dynamic, int> = 0>
|
||||||
static PYBIND11_DESCR cols() { return _("n"); }
|
static PYBIND11_DESCR cols() { return _("n"); }
|
||||||
template <typename T = Type, typename std::enable_if<T::ColsAtCompileTime != Eigen::Dynamic, int>::type = 0>
|
template <typename T = Type, enable_if_t<T::ColsAtCompileTime != Eigen::Dynamic, int> = 0>
|
||||||
static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); }
|
static PYBIND11_DESCR cols() { return _<T::ColsAtCompileTime>(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
struct type_caster<Type, typename std::enable_if<is_eigen_dense<Type>::value && is_eigen_ref<Type>::value>::type> {
|
struct type_caster<Type, enable_if_t<is_eigen_dense<Type>::value && is_eigen_ref<Type>::value>> {
|
||||||
protected:
|
protected:
|
||||||
using Derived = typename std::remove_const<typename is_eigen_ref<Type>::Derived>::type;
|
using Derived = typename std::remove_const<typename is_eigen_ref<Type>::Derived>::type;
|
||||||
using DerivedCaster = type_caster<Derived>;
|
using DerivedCaster = type_caster<Derived>;
|
||||||
@ -181,7 +181,7 @@ public:
|
|||||||
// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can
|
// type_caster for special matrix types (e.g. DiagonalMatrix): load() is not supported, but we can
|
||||||
// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that.
|
// cast them into the python domain by first copying to a regular Eigen::Matrix, then casting that.
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
struct type_caster<Type, typename std::enable_if<is_eigen_base<Type>::value && !is_eigen_ref<Type>::value>::type> {
|
struct type_caster<Type, enable_if_t<is_eigen_base<Type>::value && !is_eigen_ref<Type>::value>> {
|
||||||
protected:
|
protected:
|
||||||
using Matrix = Eigen::Matrix<typename Type::Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
using Matrix = Eigen::Matrix<typename Type::Scalar, Eigen::Dynamic, Eigen::Dynamic>;
|
||||||
using MatrixCaster = type_caster<Matrix>;
|
using MatrixCaster = type_caster<Matrix>;
|
||||||
@ -198,7 +198,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
struct type_caster<Type, typename std::enable_if<is_eigen_sparse<Type>::value>::type> {
|
struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
||||||
typedef typename Type::Scalar Scalar;
|
typedef typename Type::Scalar Scalar;
|
||||||
typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex;
|
typedef typename std::remove_reference<decltype(*std::declval<Type>().outerIndexPtr())>::type StorageIndex;
|
||||||
typedef typename Type::Index Index;
|
typedef typename Type::Index Index;
|
||||||
|
@ -486,7 +486,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct format_descriptor<T, typename std::enable_if<detail::is_pod_struct<T>::value>::type> {
|
struct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {
|
||||||
static std::string format() {
|
static std::string format() {
|
||||||
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
|
return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
|
||||||
}
|
}
|
||||||
@ -517,7 +517,7 @@ struct is_pod_struct {
|
|||||||
!std::is_same<typename std::remove_cv<T>::type, std::complex<double>>::value };
|
!std::is_same<typename std::remove_cv<T>::type, std::complex<double>>::value };
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct npy_format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> {
|
template <typename T> struct npy_format_descriptor<T, enable_if_t<std::is_integral<T>::value>> {
|
||||||
private:
|
private:
|
||||||
constexpr static const int values[8] = {
|
constexpr static const int values[8] = {
|
||||||
npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_,
|
npy_api::NPY_BYTE_, npy_api::NPY_UBYTE_, npy_api::NPY_SHORT_, npy_api::NPY_USHORT_,
|
||||||
@ -529,13 +529,13 @@ public:
|
|||||||
return object(ptr, true);
|
return object(ptr, true);
|
||||||
pybind11_fail("Unsupported buffer format!");
|
pybind11_fail("Unsupported buffer format!");
|
||||||
}
|
}
|
||||||
template <typename T2 = T, typename std::enable_if<std::is_signed<T2>::value, int>::type = 0>
|
template <typename T2 = T, enable_if_t<std::is_signed<T2>::value, int> = 0>
|
||||||
static PYBIND11_DESCR name() { return _("int") + _<sizeof(T)*8>(); }
|
static PYBIND11_DESCR name() { return _("int") + _<sizeof(T)*8>(); }
|
||||||
template <typename T2 = T, typename std::enable_if<!std::is_signed<T2>::value, int>::type = 0>
|
template <typename T2 = T, enable_if_t<!std::is_signed<T2>::value, int> = 0>
|
||||||
static PYBIND11_DESCR name() { return _("uint") + _<sizeof(T)*8>(); }
|
static PYBIND11_DESCR name() { return _("uint") + _<sizeof(T)*8>(); }
|
||||||
};
|
};
|
||||||
template <typename T> constexpr const int npy_format_descriptor<
|
template <typename T> constexpr const int npy_format_descriptor<
|
||||||
T, typename std::enable_if<std::is_integral<T>::value>::type>::values[8];
|
T, enable_if_t<std::is_integral<T>::value>>::values[8];
|
||||||
|
|
||||||
#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor<Type> { \
|
#define DECL_FMT(Type, NumPyName, Name) template<> struct npy_format_descriptor<Type> { \
|
||||||
enum { value = npy_api::NumPyName }; \
|
enum { value = npy_api::NumPyName }; \
|
||||||
@ -568,7 +568,7 @@ struct field_descriptor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct npy_format_descriptor<T, typename std::enable_if<is_pod_struct<T>::value>::type> {
|
struct npy_format_descriptor<T, enable_if_t<is_pod_struct<T>::value>> {
|
||||||
static PYBIND11_DESCR name() { return _("struct"); }
|
static PYBIND11_DESCR name() { return _("struct"); }
|
||||||
|
|
||||||
static pybind11::dtype dtype() {
|
static pybind11::dtype dtype() {
|
||||||
@ -634,9 +634,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string npy_format_descriptor<T, typename std::enable_if<is_pod_struct<T>::value>::type>::format_str;
|
std::string npy_format_descriptor<T, enable_if_t<is_pod_struct<T>::value>>::format_str;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
PyObject* npy_format_descriptor<T, typename std::enable_if<is_pod_struct<T>::value>::type>::dtype_ptr = nullptr;
|
PyObject* npy_format_descriptor<T, enable_if_t<is_pod_struct<T>::value>>::dtype_ptr = nullptr;
|
||||||
|
|
||||||
// Extract name, offset and format descriptor for a struct field
|
// Extract name, offset and format descriptor for a struct field
|
||||||
#define PYBIND11_FIELD_DESCRIPTOR(Type, Field) \
|
#define PYBIND11_FIELD_DESCRIPTOR(Type, Field) \
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
#if defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||||
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
|
# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
|
||||||
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
|
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
|
||||||
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
|
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
|
||||||
|
# pragma warning(disable: 4702) // warning C4702: unreachable code
|
||||||
#elif defined(__INTEL_COMPILER)
|
#elif defined(__INTEL_COMPILER)
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
|
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
|
||||||
@ -460,8 +461,10 @@ protected:
|
|||||||
if (overloads->is_operator)
|
if (overloads->is_operator)
|
||||||
return handle(Py_NotImplemented).inc_ref().ptr();
|
return handle(Py_NotImplemented).inc_ref().ptr();
|
||||||
|
|
||||||
std::string msg = "Incompatible " + std::string(overloads->is_constructor ? "constructor" : "function") +
|
std::string msg = std::string(overloads->name) + "(): incompatible " +
|
||||||
" arguments. The following argument types are supported:\n";
|
std::string(overloads->is_constructor ? "constructor" : "function") +
|
||||||
|
" arguments. The following argument types are supported:\n";
|
||||||
|
|
||||||
int ctr = 0;
|
int ctr = 0;
|
||||||
for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
|
for (detail::function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {
|
||||||
msg += " "+ std::to_string(++ctr) + ". ";
|
msg += " "+ std::to_string(++ctr) + ". ";
|
||||||
@ -489,7 +492,7 @@ protected:
|
|||||||
|
|
||||||
msg += "\n";
|
msg += "\n";
|
||||||
}
|
}
|
||||||
msg += " Invoked with: ";
|
msg += "\nInvoked with: ";
|
||||||
tuple args_(args, true);
|
tuple args_(args, true);
|
||||||
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
|
for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {
|
||||||
msg += static_cast<std::string>(static_cast<object>(args_[ti]).str());
|
msg += static_cast<std::string>(static_cast<object>(args_[ti]).str());
|
||||||
@ -574,18 +577,6 @@ public:
|
|||||||
PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)
|
PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)
|
||||||
protected:
|
protected:
|
||||||
void initialize(type_record *rec) {
|
void initialize(type_record *rec) {
|
||||||
if (rec->base_type) {
|
|
||||||
if (rec->base_handle)
|
|
||||||
pybind11_fail("generic_type: specified base type multiple times!");
|
|
||||||
rec->base_handle = detail::get_type_handle(*(rec->base_type));
|
|
||||||
if (!rec->base_handle) {
|
|
||||||
std::string tname(rec->base_type->name());
|
|
||||||
detail::clean_type_id(tname);
|
|
||||||
pybind11_fail("generic_type: type \"" + std::string(rec->name) +
|
|
||||||
"\" referenced unknown base type \"" + tname + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &internals = get_internals();
|
auto &internals = get_internals();
|
||||||
auto tindex = std::type_index(*(rec->type));
|
auto tindex = std::type_index(*(rec->type));
|
||||||
|
|
||||||
@ -615,6 +606,12 @@ protected:
|
|||||||
ht_qualname = name;
|
ht_qualname = name;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
size_t num_bases = rec->bases.size();
|
||||||
|
tuple bases(num_bases);
|
||||||
|
for (size_t i = 0; i < num_bases; ++i)
|
||||||
|
bases[i] = rec->bases[i];
|
||||||
|
|
||||||
std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name)
|
std::string full_name = (scope_module ? ((std::string) scope_module.str() + "." + rec->name)
|
||||||
: std::string(rec->name));
|
: std::string(rec->name));
|
||||||
|
|
||||||
@ -627,11 +624,16 @@ protected:
|
|||||||
memcpy((void *) tp_doc, rec->doc, size);
|
memcpy((void *) tp_doc, rec->doc, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Danger zone: from now (and until PyType_Ready), make sure to
|
||||||
|
issue no Python C API calls which could potentially invoke the
|
||||||
|
garbage collector (the GC will call type_traverse(), which will in
|
||||||
|
turn find the newly constructed type in an invalid state) */
|
||||||
|
|
||||||
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
|
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
|
||||||
auto type = (PyHeapTypeObject*) type_holder.ptr();
|
auto type = (PyHeapTypeObject*) type_holder.ptr();
|
||||||
|
|
||||||
if (!type_holder || !name)
|
if (!type_holder || !name)
|
||||||
pybind11_fail("generic_type: unable to create type object!");
|
pybind11_fail(std::string(rec->name) + ": Unable to create type object!");
|
||||||
|
|
||||||
/* Register supplemental type information in C++ dict */
|
/* Register supplemental type information in C++ dict */
|
||||||
detail::type_info *tinfo = new detail::type_info();
|
detail::type_info *tinfo = new detail::type_info();
|
||||||
@ -644,8 +646,12 @@ protected:
|
|||||||
/* Basic type attributes */
|
/* Basic type attributes */
|
||||||
type->ht_type.tp_name = strdup(full_name.c_str());
|
type->ht_type.tp_name = strdup(full_name.c_str());
|
||||||
type->ht_type.tp_basicsize = (ssize_t) rec->instance_size;
|
type->ht_type.tp_basicsize = (ssize_t) rec->instance_size;
|
||||||
type->ht_type.tp_base = (PyTypeObject *) rec->base_handle.ptr();
|
|
||||||
rec->base_handle.inc_ref();
|
if (num_bases > 0) {
|
||||||
|
type->ht_type.tp_base = (PyTypeObject *) ((object) bases[0]).inc_ref().ptr();
|
||||||
|
type->ht_type.tp_bases = bases.release().ptr();
|
||||||
|
rec->multiple_inheritance |= num_bases > 1;
|
||||||
|
}
|
||||||
|
|
||||||
type->ht_name = name.release().ptr();
|
type->ht_name = name.release().ptr();
|
||||||
|
|
||||||
@ -676,7 +682,8 @@ protected:
|
|||||||
type->ht_type.tp_doc = tp_doc;
|
type->ht_type.tp_doc = tp_doc;
|
||||||
|
|
||||||
if (PyType_Ready(&type->ht_type) < 0)
|
if (PyType_Ready(&type->ht_type) < 0)
|
||||||
pybind11_fail("generic_type: PyType_Ready failed!");
|
pybind11_fail(std::string(rec->name) + ": PyType_Ready failed (" +
|
||||||
|
detail::error_string() + ")!");
|
||||||
|
|
||||||
m_ptr = type_holder.ptr();
|
m_ptr = type_holder.ptr();
|
||||||
|
|
||||||
@ -687,9 +694,23 @@ protected:
|
|||||||
if (rec->scope)
|
if (rec->scope)
|
||||||
rec->scope.attr(handle(type->ht_name)) = *this;
|
rec->scope.attr(handle(type->ht_name)) = *this;
|
||||||
|
|
||||||
|
if (rec->multiple_inheritance)
|
||||||
|
mark_parents_nonsimple(&type->ht_type);
|
||||||
|
|
||||||
type_holder.release();
|
type_holder.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function which tags all parents of a type using mult. inheritance
|
||||||
|
void mark_parents_nonsimple(PyTypeObject *value) {
|
||||||
|
tuple t(value->tp_bases, true);
|
||||||
|
for (handle h : t) {
|
||||||
|
auto tinfo2 = get_type_info((PyTypeObject *) h.ptr());
|
||||||
|
if (tinfo2)
|
||||||
|
tinfo2->simple_type = false;
|
||||||
|
mark_parents_nonsimple((PyTypeObject *) h.ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocate a metaclass on demand (for static properties)
|
/// Allocate a metaclass on demand (for static properties)
|
||||||
handle metaclass() {
|
handle metaclass() {
|
||||||
auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
|
auto &ht_type = ((PyHeapTypeObject *) m_ptr)->ht_type;
|
||||||
@ -809,31 +830,18 @@ protected:
|
|||||||
static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
|
static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template<typename> class Predicate, typename... BaseTypes> struct class_selector;
|
|
||||||
template <template<typename> class Predicate, typename Base, typename... Bases>
|
|
||||||
struct class_selector<Predicate, Base, Bases...> {
|
|
||||||
static inline void set_bases(detail::type_record &record) {
|
|
||||||
if (Predicate<Base>::value) record.base_type = &typeid(Base);
|
|
||||||
else class_selector<Predicate, Bases...>::set_bases(record);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template <template<typename> class Predicate>
|
|
||||||
struct class_selector<Predicate> {
|
|
||||||
static inline void set_bases(detail::type_record &) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
template <typename type_, typename... options>
|
template <typename type_, typename... options>
|
||||||
class class_ : public detail::generic_type {
|
class class_ : public detail::generic_type {
|
||||||
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
|
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
|
||||||
template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
|
template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
|
||||||
template <typename T> using is_base_class = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
|
template <typename T> using is_base = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
|
||||||
template <typename T> using is_valid_class_option =
|
template <typename T> using is_valid_class_option =
|
||||||
detail::bool_constant<
|
detail::bool_constant<
|
||||||
is_holder<T>::value ||
|
is_holder<T>::value ||
|
||||||
is_subtype<T>::value ||
|
is_subtype<T>::value ||
|
||||||
is_base_class<T>::value
|
is_base<T>::value
|
||||||
>;
|
>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -846,9 +854,6 @@ public:
|
|||||||
static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
|
static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
|
||||||
"Unknown/invalid class_ template parameters provided");
|
"Unknown/invalid class_ template parameters provided");
|
||||||
|
|
||||||
static_assert(detail::count_t<is_base_class, options...>::value <= 1,
|
|
||||||
"Invalid class_ base types: multiple inheritance is not supported");
|
|
||||||
|
|
||||||
PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check)
|
PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check)
|
||||||
|
|
||||||
template <typename... Extra>
|
template <typename... Extra>
|
||||||
@ -862,7 +867,9 @@ public:
|
|||||||
record.init_holder = init_holder;
|
record.init_holder = init_holder;
|
||||||
record.dealloc = dealloc;
|
record.dealloc = dealloc;
|
||||||
|
|
||||||
detail::class_selector<is_base_class, options...>::set_bases(record);
|
/* Register base classes specified via template arguments to class_, if any */
|
||||||
|
bool unused[] = { (add_base<options>(record), false)..., false };
|
||||||
|
(void) unused;
|
||||||
|
|
||||||
/* Process optional arguments, if any */
|
/* Process optional arguments, if any */
|
||||||
detail::process_attributes<Extra...>::init(extra..., &record);
|
detail::process_attributes<Extra...>::init(extra..., &record);
|
||||||
@ -875,6 +882,16 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>
|
||||||
|
static void add_base(detail::type_record &rec) {
|
||||||
|
rec.add_base(&typeid(Base), [](void *src) -> void * {
|
||||||
|
return static_cast<Base *>(reinterpret_cast<type *>(src));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Base, detail::enable_if_t<!is_base<Base>::value, int> = 0>
|
||||||
|
static void add_base(detail::type_record &) { }
|
||||||
|
|
||||||
template <typename Func, typename... Extra>
|
template <typename Func, typename... Extra>
|
||||||
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
|
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
|
||||||
cpp_function cf(std::forward<Func>(f), name(name_),
|
cpp_function cf(std::forward<Func>(f), name(name_),
|
||||||
@ -1016,7 +1033,7 @@ private:
|
|||||||
|
|
||||||
/// Initialize holder object, variant 2: try to construct from existing holder object, if possible
|
/// Initialize holder object, variant 2: try to construct from existing holder object, if possible
|
||||||
template <typename T = holder_type,
|
template <typename T = holder_type,
|
||||||
typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
|
detail::enable_if_t<std::is_copy_constructible<T>::value, int> = 0>
|
||||||
static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) {
|
static void init_holder_helper(instance_type *inst, const holder_type *holder_ptr, const void * /* dummy */) {
|
||||||
if (holder_ptr)
|
if (holder_ptr)
|
||||||
new (&inst->holder) holder_type(*holder_ptr);
|
new (&inst->holder) holder_type(*holder_ptr);
|
||||||
@ -1026,7 +1043,7 @@ private:
|
|||||||
|
|
||||||
/// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer
|
/// Initialize holder object, variant 3: holder is not copy constructible (e.g. unique_ptr), always initialize from raw pointer
|
||||||
template <typename T = holder_type,
|
template <typename T = holder_type,
|
||||||
typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
|
detail::enable_if_t<!std::is_copy_constructible<T>::value, int> = 0>
|
||||||
static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) {
|
static void init_holder_helper(instance_type *inst, const holder_type * /* unused */, const void * /* dummy */) {
|
||||||
new (&inst->holder) holder_type(inst->value);
|
new (&inst->holder) holder_type(inst->value);
|
||||||
}
|
}
|
||||||
@ -1196,7 +1213,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||||||
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
|
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
|
||||||
typedef detail::iterator_state<Iterator, Sentinel, false, Policy> state;
|
typedef detail::iterator_state<Iterator, Sentinel, false, Policy> state;
|
||||||
|
|
||||||
if (!detail::get_type_info(typeid(state))) {
|
if (!detail::get_type_info(typeid(state), false)) {
|
||||||
class_<state>(handle(), "iterator")
|
class_<state>(handle(), "iterator")
|
||||||
.def("__iter__", [](state &s) -> state& { return s; })
|
.def("__iter__", [](state &s) -> state& { return s; })
|
||||||
.def("__next__", [](state &s) -> ValueType {
|
.def("__next__", [](state &s) -> ValueType {
|
||||||
@ -1221,7 +1238,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
|||||||
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
|
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
|
||||||
typedef detail::iterator_state<Iterator, Sentinel, true, Policy> state;
|
typedef detail::iterator_state<Iterator, Sentinel, true, Policy> state;
|
||||||
|
|
||||||
if (!detail::get_type_info(typeid(state))) {
|
if (!detail::get_type_info(typeid(state), false)) {
|
||||||
class_<state>(handle(), "iterator")
|
class_<state>(handle(), "iterator")
|
||||||
.def("__iter__", [](state &s) -> state& { return s; })
|
.def("__iter__", [](state &s) -> state& { return s; })
|
||||||
.def("__next__", [](state &s) -> KeyType {
|
.def("__next__", [](state &s) -> KeyType {
|
||||||
|
@ -43,10 +43,8 @@ public:
|
|||||||
bool is_none() const { return m_ptr == Py_None; }
|
bool is_none() const { return m_ptr == Py_None; }
|
||||||
template <typename T> T cast() const;
|
template <typename T> T cast() const;
|
||||||
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
|
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
|
||||||
#if __cplusplus > 201103L
|
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
|
||||||
[[deprecated("call(...) was deprecated in favor of operator()(...)")]]
|
object call(Args&&... args) const;
|
||||||
#endif
|
|
||||||
object call(Args&&... args) const;
|
|
||||||
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
|
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
|
||||||
object operator()(Args&&... args) const;
|
object operator()(Args&&... args) const;
|
||||||
operator bool() const { return m_ptr != nullptr; }
|
operator bool() const { return m_ptr != nullptr; }
|
||||||
@ -492,7 +490,7 @@ class int_ : public object {
|
|||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT_DEFAULT(int_, object, PYBIND11_LONG_CHECK)
|
PYBIND11_OBJECT_DEFAULT(int_, object, PYBIND11_LONG_CHECK)
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||||
int_(T value) {
|
int_(T value) {
|
||||||
if (sizeof(T) <= sizeof(long)) {
|
if (sizeof(T) <= sizeof(long)) {
|
||||||
if (std::is_signed<T>::value)
|
if (std::is_signed<T>::value)
|
||||||
@ -509,7 +507,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
detail::enable_if_t<std::is_integral<T>::value, int> = 0>
|
||||||
operator T() const {
|
operator T() const {
|
||||||
if (sizeof(T) <= sizeof(long)) {
|
if (sizeof(T) <= sizeof(long)) {
|
||||||
if (std::is_signed<T>::value)
|
if (std::is_signed<T>::value)
|
||||||
@ -614,7 +612,7 @@ public:
|
|||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||||
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
||||||
void append(const object &object) const { PyList_Append(m_ptr, object.ptr()); }
|
void append(handle h) const { PyList_Append(m_ptr, h.ptr()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
|
class args : public tuple { PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check) };
|
||||||
|
@ -112,7 +112,7 @@ template <typename Type, typename Value> struct list_caster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = Type,
|
template <typename T = Type,
|
||||||
typename std::enable_if<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int>::type = 0>
|
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
|
||||||
void reserve_maybe(list l, Type *) { value.reserve(l.size()); }
|
void reserve_maybe(list l, Type *) { value.reserve(l.size()); }
|
||||||
void reserve_maybe(list, void *) { }
|
void reserve_maybe(list, void *) { }
|
||||||
|
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "operators.h"
|
#include "operators.h"
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -42,20 +40,20 @@ struct is_comparable : std::false_type { };
|
|||||||
/* For non-map data structures, check whether operator== can be instantiated */
|
/* For non-map data structures, check whether operator== can be instantiated */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<
|
struct is_comparable<
|
||||||
T, typename std::enable_if<container_traits<T>::is_element &&
|
T, enable_if_t<container_traits<T>::is_element &&
|
||||||
container_traits<T>::is_comparable>::type>
|
container_traits<T>::is_comparable>>
|
||||||
: std::true_type { };
|
: std::true_type { };
|
||||||
|
|
||||||
/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
|
/* For a vector/map data structure, recursively check the value type (which is std::pair for maps) */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<T, typename std::enable_if<container_traits<T>::is_vector>::type> {
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_vector>> {
|
||||||
static constexpr const bool value =
|
static constexpr const bool value =
|
||||||
is_comparable<typename T::value_type>::value;
|
is_comparable<typename T::value_type>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For pairs, recursively check the two data types */
|
/* For pairs, recursively check the two data types */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_comparable<T, typename std::enable_if<container_traits<T>::is_pair>::type> {
|
struct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {
|
||||||
static constexpr const bool value =
|
static constexpr const bool value =
|
||||||
is_comparable<typename T::first_type>::value &&
|
is_comparable<typename T::first_type>::value &&
|
||||||
is_comparable<typename T::second_type>::value;
|
is_comparable<typename T::second_type>::value;
|
||||||
@ -66,13 +64,13 @@ template <typename, typename, typename... Args> void vector_if_copy_constructibl
|
|||||||
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args&...) { }
|
template <typename, typename, typename... Args> void vector_if_equal_operator(const Args&...) { }
|
||||||
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args&...) { }
|
template <typename, typename, typename... Args> void vector_if_insertion_operator(const Args&...) { }
|
||||||
|
|
||||||
template<typename Vector, typename Class_, typename std::enable_if<std::is_copy_constructible<typename Vector::value_type>::value, int>::type = 0>
|
template<typename Vector, typename Class_, enable_if_t<std::is_copy_constructible<typename Vector::value_type>::value, int> = 0>
|
||||||
void vector_if_copy_constructible(Class_ &cl) {
|
void vector_if_copy_constructible(Class_ &cl) {
|
||||||
cl.def(pybind11::init<const Vector &>(),
|
cl.def(pybind11::init<const Vector &>(),
|
||||||
"Copy constructor");
|
"Copy constructor");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Vector, typename Class_, typename std::enable_if<is_comparable<Vector>::value, int>::type = 0>
|
template<typename Vector, typename Class_, enable_if_t<is_comparable<Vector>::value, int> = 0>
|
||||||
void vector_if_equal_operator(Class_ &cl) {
|
void vector_if_equal_operator(Class_ &cl) {
|
||||||
using T = typename Vector::value_type;
|
using T = typename Vector::value_type;
|
||||||
|
|
||||||
@ -378,7 +376,7 @@ template <typename Map, typename Class_, typename... Args> void map_if_copy_assi
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Map, typename Class_, typename std::enable_if<!std::is_copy_assignable<typename Map::mapped_type>::value, int>::type = 0>
|
template<typename Map, typename Class_, enable_if_t<!std::is_copy_assignable<typename Map::mapped_type>::value, int> = 0>
|
||||||
void map_if_copy_assignable(Class_ &cl) {
|
void map_if_copy_assignable(Class_ &cl) {
|
||||||
using KeyType = typename Map::key_type;
|
using KeyType = typename Map::key_type;
|
||||||
using MappedType = typename Map::mapped_type;
|
using MappedType = typename Map::mapped_type;
|
||||||
|
@ -29,9 +29,9 @@ set(PYBIND11_TEST_FILES
|
|||||||
test_pickling.cpp
|
test_pickling.cpp
|
||||||
test_python_types.cpp
|
test_python_types.cpp
|
||||||
test_sequences_and_iterators.cpp
|
test_sequences_and_iterators.cpp
|
||||||
test_smart_ptr.cpp
|
|
||||||
test_stl_binders.cpp
|
test_stl_binders.cpp
|
||||||
test_virtual_functions.cpp
|
test_virtual_functions.cpp
|
||||||
|
test_multiple_inheritance.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}")
|
||||||
|
@ -83,7 +83,7 @@ def test_cpp_function_roundtrip():
|
|||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
test_dummy_function(dummy_function2)
|
test_dummy_function(dummy_function2)
|
||||||
assert "Incompatible function arguments" in str(excinfo.value)
|
assert "incompatible function arguments" in str(excinfo.value)
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
test_dummy_function(lambda x, y: x + y)
|
test_dummy_function(lambda x, y: x + y)
|
||||||
|
@ -61,7 +61,7 @@ test_initializer inheritance([](py::module &m) {
|
|||||||
.def(py::init<std::string>());
|
.def(py::init<std::string>());
|
||||||
|
|
||||||
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
/* Another way of declaring a subclass relationship: reference parent's C++ type */
|
||||||
py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
|
py::class_<Rabbit, Pet>(m, "Rabbit")
|
||||||
.def(py::init<std::string>());
|
.def(py::init<std::string>());
|
||||||
|
|
||||||
/* And another: list parent in class template arguments */
|
/* And another: list parent in class template arguments */
|
||||||
|
@ -24,9 +24,10 @@ def test_inheritance(msg):
|
|||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
dog_bark(polly)
|
dog_bark(polly)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible function arguments. The following argument types are supported:
|
dog_bark(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: m.Dog) -> str
|
1. (arg0: m.Dog) -> str
|
||||||
Invoked with: <m.Pet object at 0>
|
|
||||||
|
Invoked with: <m.Pet object at 0>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,17 +65,19 @@ def test_no_id(capture, msg):
|
|||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_element(None)
|
get_element(None)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible function arguments. The following argument types are supported:
|
get_element(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: m.issues.ElementA) -> int
|
1. (arg0: m.issues.ElementA) -> int
|
||||||
Invoked with: None
|
|
||||||
|
Invoked with: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
expect_int(5.2)
|
expect_int(5.2)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible function arguments. The following argument types are supported:
|
expect_int(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: int) -> int
|
1. (arg0: int) -> int
|
||||||
Invoked with: 5.2
|
|
||||||
|
Invoked with: 5.2
|
||||||
"""
|
"""
|
||||||
assert expect_float(12) == 12
|
assert expect_float(12) == 12
|
||||||
|
|
||||||
@ -90,10 +92,11 @@ def test_str_issue(msg):
|
|||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
str(StrIssue("no", "such", "constructor"))
|
str(StrIssue("no", "such", "constructor"))
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible constructor arguments. The following argument types are supported:
|
__init__(): incompatible constructor arguments. The following argument types are supported:
|
||||||
1. m.issues.StrIssue(arg0: int)
|
1. m.issues.StrIssue(arg0: int)
|
||||||
2. m.issues.StrIssue()
|
2. m.issues.StrIssue()
|
||||||
Invoked with: no, such, constructor
|
|
||||||
|
Invoked with: no, such, constructor
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,9 +35,10 @@ def test_named_arguments(msg):
|
|||||||
# noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
kw_func2(x=5, y=10, z=12)
|
kw_func2(x=5, y=10, z=12)
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible function arguments. The following argument types are supported:
|
kw_func2(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (x: int=100, y: int=200) -> str
|
1. (x: int=100, y: int=200) -> str
|
||||||
Invoked with:
|
|
||||||
|
Invoked with:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert kw_func4() == "{13 17}"
|
assert kw_func4() == "{13 17}"
|
||||||
|
85
tests/test_multiple_inheritance.cpp
Normal file
85
tests/test_multiple_inheritance.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
tests/test_multiple_inheritance.cpp -- multiple inheritance,
|
||||||
|
implicit MI casts
|
||||||
|
|
||||||
|
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
||||||
|
|
||||||
|
All rights reserved. Use of this source code is governed by a
|
||||||
|
BSD-style license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pybind11_tests.h"
|
||||||
|
|
||||||
|
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);
|
||||||
|
|
||||||
|
struct Base1 {
|
||||||
|
Base1(int i) : i(i) { }
|
||||||
|
int foo() { return i; }
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Base2 {
|
||||||
|
Base2(int i) : i(i) { }
|
||||||
|
int bar() { return i; }
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Base12 : Base1, Base2 {
|
||||||
|
Base12(int i, int j) : Base1(i), Base2(j) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MIType : Base12 {
|
||||||
|
MIType(int i, int j) : Base12(i, j) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
test_initializer multiple_inheritance([](py::module &m) {
|
||||||
|
py::class_<Base1>(m, "Base1")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("foo", &Base1::foo);
|
||||||
|
|
||||||
|
py::class_<Base2>(m, "Base2")
|
||||||
|
.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>());
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Test the case where not all base classes are specified,
|
||||||
|
and where pybind11 requires the py::multiple_inheritance
|
||||||
|
flag to perform proper casting between types */
|
||||||
|
|
||||||
|
struct Base1a {
|
||||||
|
Base1a(int i) : i(i) { }
|
||||||
|
int foo() { return i; }
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Base2a {
|
||||||
|
Base2a(int i) : i(i) { }
|
||||||
|
int bar() { return i; }
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Base12a : Base1a, Base2a {
|
||||||
|
Base12a(int i, int j) : Base1a(i), Base2a(j) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
test_initializer multiple_inheritance_nonexplicit([](py::module &m) {
|
||||||
|
py::class_<Base1a, std::shared_ptr<Base1a>>(m, "Base1a")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("foo", &Base1a::foo);
|
||||||
|
|
||||||
|
py::class_<Base2a, std::shared_ptr<Base2a>>(m, "Base2a")
|
||||||
|
.def(py::init<int>())
|
||||||
|
.def("bar", &Base2a::bar);
|
||||||
|
|
||||||
|
py::class_<Base12a, /* Base1 missing */ Base2a,
|
||||||
|
std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance())
|
||||||
|
.def(py::init<int, int>());
|
||||||
|
|
||||||
|
m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
|
||||||
|
m.def("bar_base2a_sharedptr", [](std::shared_ptr<Base2a> b) { return b->bar(); });
|
||||||
|
});
|
65
tests/test_multiple_inheritance.py
Normal file
65
tests/test_multiple_inheritance.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_inheritance_cpp(msg):
|
||||||
|
from pybind11_tests import MIType
|
||||||
|
|
||||||
|
mt = MIType(3, 4)
|
||||||
|
|
||||||
|
assert mt.foo() == 3
|
||||||
|
assert mt.bar() == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_inheritance_mix1(msg):
|
||||||
|
from pybind11_tests import Base2
|
||||||
|
|
||||||
|
class Base1:
|
||||||
|
def __init__(self, i):
|
||||||
|
self.i = i
|
||||||
|
|
||||||
|
def foo(self):
|
||||||
|
return self.i
|
||||||
|
|
||||||
|
class MITypePy(Base1, Base2):
|
||||||
|
def __init__(self, i, j):
|
||||||
|
Base1.__init__(self, i)
|
||||||
|
Base2.__init__(self, j)
|
||||||
|
|
||||||
|
mt = MITypePy(3, 4)
|
||||||
|
|
||||||
|
assert mt.foo() == 3
|
||||||
|
assert mt.bar() == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_inheritance_mix2(msg):
|
||||||
|
from pybind11_tests import Base1
|
||||||
|
|
||||||
|
class Base2:
|
||||||
|
def __init__(self, i):
|
||||||
|
self.i = i
|
||||||
|
|
||||||
|
def bar(self):
|
||||||
|
return self.i
|
||||||
|
|
||||||
|
class MITypePy(Base1, Base2):
|
||||||
|
def __init__(self, i, j):
|
||||||
|
Base1.__init__(self, i)
|
||||||
|
Base2.__init__(self, j)
|
||||||
|
|
||||||
|
mt = MITypePy(3, 4)
|
||||||
|
|
||||||
|
assert mt.foo() == 3
|
||||||
|
assert mt.bar() == 4
|
||||||
|
|
||||||
|
|
||||||
|
def test_multiple_inheritance_virtbase(msg):
|
||||||
|
from pybind11_tests import Base12a, bar_base2a, bar_base2a_sharedptr
|
||||||
|
|
||||||
|
class MITypePy(Base12a):
|
||||||
|
def __init__(self, i, j):
|
||||||
|
Base12a.__init__(self, i, j)
|
||||||
|
|
||||||
|
mt = MITypePy(3, 4)
|
||||||
|
assert mt.bar() == 4
|
||||||
|
assert bar_base2a(mt) == 4
|
||||||
|
assert bar_base2a_sharedptr(mt) == 4
|
@ -35,9 +35,10 @@ def test_pointers(msg):
|
|||||||
with pytest.raises(TypeError) as excinfo:
|
with pytest.raises(TypeError) as excinfo:
|
||||||
get_void_ptr_value([1, 2, 3]) # This should not work
|
get_void_ptr_value([1, 2, 3]) # This should not work
|
||||||
assert msg(excinfo.value) == """
|
assert msg(excinfo.value) == """
|
||||||
Incompatible function arguments. The following argument types are supported:
|
get_void_ptr_value(): incompatible function arguments. The following argument types are supported:
|
||||||
1. (arg0: capsule) -> int
|
1. (arg0: capsule) -> int
|
||||||
Invoked with: [1, 2, 3]
|
|
||||||
|
Invoked with: [1, 2, 3]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert return_null_str() is None
|
assert return_null_str() is None
|
||||||
|
Loading…
Reference in New Issue
Block a user