mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-27 07:32:02 +00:00
Merge branch 'pybind:master' into master
This commit is contained in:
commit
611c5aecc2
@ -1161,6 +1161,58 @@ error:
|
|||||||
|
|
||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
|
Binding classes with template parameters
|
||||||
|
========================================
|
||||||
|
|
||||||
|
pybind11 can also wrap classes that have template parameters. Consider these classes:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
struct Cat {};
|
||||||
|
struct Dog {};
|
||||||
|
|
||||||
|
template <typename PetType>
|
||||||
|
struct Cage {
|
||||||
|
Cage(PetType& pet);
|
||||||
|
PetType& get();
|
||||||
|
};
|
||||||
|
|
||||||
|
C++ templates may only be instantiated at compile time, so pybind11 can only
|
||||||
|
wrap instantiated templated classes. You cannot wrap a non-instantiated template:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// BROKEN (this will not compile)
|
||||||
|
py::class_<Cage>(m, "Cage");
|
||||||
|
.def("get", &Cage::get);
|
||||||
|
|
||||||
|
You must explicitly specify each template/type combination that you want to
|
||||||
|
wrap separately.
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// ok
|
||||||
|
py::class_<Cage<Cat>>(m, "CatCage")
|
||||||
|
.def("get", &Cage<Cat>::get);
|
||||||
|
|
||||||
|
// ok
|
||||||
|
py::class_<Cage<Dog>>(m, "DogCage")
|
||||||
|
.def("get", &Cage<Dog>::get);
|
||||||
|
|
||||||
|
If your class methods have template parameters you can wrap those as well,
|
||||||
|
but once again each instantiation must be explicitly specified:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
typename <typename T>
|
||||||
|
struct MyClass {
|
||||||
|
template <typename V>
|
||||||
|
T fn(V v);
|
||||||
|
};
|
||||||
|
|
||||||
|
py::class<MyClass<int>>(m, "MyClassT")
|
||||||
|
.def("fn", &MyClass<int>::fn<std::string>);
|
||||||
|
|
||||||
Custom automatic downcasters
|
Custom automatic downcasters
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
@ -578,3 +578,38 @@ prefers earlier-defined overloads to later-defined ones.
|
|||||||
.. versionadded:: 2.6
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
The ``py::prepend()`` tag.
|
The ``py::prepend()`` tag.
|
||||||
|
|
||||||
|
Binding functions with template parameters
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
You can bind functions that have template parameters. Here's a function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void set(T t);
|
||||||
|
|
||||||
|
C++ templates cannot be instantiated at runtime, so you cannot bind the
|
||||||
|
non-instantiated function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
// BROKEN (this will not compile)
|
||||||
|
m.def("set", &set);
|
||||||
|
|
||||||
|
You must bind each instantiated function template separately. You may bind
|
||||||
|
each instantiation with the same name, which will be treated the same as
|
||||||
|
an overloaded function:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("set", &set<int>);
|
||||||
|
m.def("set", &set<std::string>);
|
||||||
|
|
||||||
|
Sometimes it's more clear to bind them with separate names, which is also
|
||||||
|
an option:
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
m.def("setInt", &set<int>);
|
||||||
|
m.def("setString", &set<std::string>);
|
||||||
|
@ -200,7 +200,9 @@ struct type_info {
|
|||||||
void *get_buffer_data = nullptr;
|
void *get_buffer_data = nullptr;
|
||||||
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
void *(*module_local_load)(PyObject *, const type_info *) = nullptr;
|
||||||
/* A simple type never occurs as a (direct or indirect) parent
|
/* A simple type never occurs as a (direct or indirect) parent
|
||||||
* of a class that makes use of multiple inheritance */
|
* of a class that makes use of multiple inheritance.
|
||||||
|
* A type can be simple even if it has non-simple ancestors as long as it has no descendants.
|
||||||
|
*/
|
||||||
bool simple_type : 1;
|
bool simple_type : 1;
|
||||||
/* True if there is no multiple inheritance in this type's inheritance tree */
|
/* True if there is no multiple inheritance in this type's inheritance tree */
|
||||||
bool simple_ancestors : 1;
|
bool simple_ancestors : 1;
|
||||||
@ -322,7 +324,7 @@ inline bool raise_err(PyObject *exc_type, const char *msg) {
|
|||||||
#endif
|
#endif
|
||||||
PyErr_SetString(exc_type, msg);
|
PyErr_SetString(exc_type, msg);
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
inline void translate_exception(std::exception_ptr p) {
|
inline void translate_exception(std::exception_ptr p) {
|
||||||
if (!p) {
|
if (!p) {
|
||||||
|
@ -177,10 +177,10 @@ struct npy_api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PyArray_Check_(PyObject *obj) const {
|
bool PyArray_Check_(PyObject *obj) const {
|
||||||
return (bool) PyObject_TypeCheck(obj, PyArray_Type_);
|
return PyObject_TypeCheck(obj, PyArray_Type_) != 0;
|
||||||
}
|
}
|
||||||
bool PyArrayDescr_Check_(PyObject *obj) const {
|
bool PyArrayDescr_Check_(PyObject *obj) const {
|
||||||
return (bool) PyObject_TypeCheck(obj, PyArrayDescr_Type_);
|
return PyObject_TypeCheck(obj, PyArrayDescr_Type_) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
|
unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();
|
||||||
|
@ -988,6 +988,13 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
append_note_if_missing_header_is_suspected(msg);
|
append_note_if_missing_header_is_suspected(msg);
|
||||||
|
#if PY_VERSION_HEX >= 0x03030000
|
||||||
|
// Attach additional error info to the exception if supported
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
raise_from(PyExc_TypeError, msg.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -1206,13 +1213,14 @@ protected:
|
|||||||
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
|
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
|
||||||
mark_parents_nonsimple(tinfo->type);
|
mark_parents_nonsimple(tinfo->type);
|
||||||
tinfo->simple_ancestors = false;
|
tinfo->simple_ancestors = false;
|
||||||
tinfo->simple_type = false;
|
|
||||||
}
|
}
|
||||||
else if (rec.bases.size() == 1) {
|
else if (rec.bases.size() == 1) {
|
||||||
auto parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());
|
auto *parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());
|
||||||
tinfo->simple_ancestors = parent_tinfo->simple_ancestors;
|
assert(parent_tinfo != nullptr);
|
||||||
// a child of a non-simple type can never be a simple type
|
bool parent_simple_ancestors = parent_tinfo->simple_ancestors;
|
||||||
tinfo->simple_type = parent_tinfo->simple_type;
|
tinfo->simple_ancestors = parent_simple_ancestors;
|
||||||
|
// The parent can no longer be a simple type if it has MI and has a child
|
||||||
|
parent_tinfo->simple_type = parent_tinfo->simple_type && parent_simple_ancestors;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec.module_local) {
|
if (rec.module_local) {
|
||||||
|
7
setup.py
7
setup.py
@ -146,6 +146,13 @@ with remove_output("pybind11/include", "pybind11/share"):
|
|||||||
"-DBUILD_TESTING=OFF",
|
"-DBUILD_TESTING=OFF",
|
||||||
"-DPYBIND11_NOPYTHON=ON",
|
"-DPYBIND11_NOPYTHON=ON",
|
||||||
]
|
]
|
||||||
|
if "CMAKE_ARGS" in os.environ:
|
||||||
|
fcommand = [
|
||||||
|
c
|
||||||
|
for c in os.environ["CMAKE_ARGS"].split()
|
||||||
|
if "DCMAKE_INSTALL_PREFIX" not in c
|
||||||
|
]
|
||||||
|
cmd += fcommand
|
||||||
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
cmake_opts = dict(cwd=DIR, stdout=sys.stdout, stderr=sys.stderr)
|
||||||
subprocess.check_call(cmd, **cmake_opts)
|
subprocess.check_call(cmd, **cmake_opts)
|
||||||
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
subprocess.check_call(["cmake", "--install", tmpdir], **cmake_opts)
|
||||||
|
@ -472,3 +472,25 @@ def test_pr3635_diamond_f():
|
|||||||
assert o.get_f_e() == 5
|
assert o.get_f_e() == 5
|
||||||
|
|
||||||
assert o.get_f_f() == 6
|
assert o.get_f_f() == 6
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_inherit_from_mi():
|
||||||
|
"""Tests extending a Python class from a single inheritor of a MI class"""
|
||||||
|
|
||||||
|
class PyMVF(m.MVF):
|
||||||
|
g = 7
|
||||||
|
|
||||||
|
def get_g_g(self):
|
||||||
|
return self.g
|
||||||
|
|
||||||
|
o = PyMVF()
|
||||||
|
|
||||||
|
assert o.b == 1
|
||||||
|
assert o.c == 2
|
||||||
|
assert o.d0 == 3
|
||||||
|
assert o.d1 == 4
|
||||||
|
assert o.e == 5
|
||||||
|
assert o.f == 6
|
||||||
|
assert o.g == 7
|
||||||
|
|
||||||
|
assert o.get_g_g() == 7
|
||||||
|
@ -110,7 +110,7 @@ if(NOT DEFINED PYTHON_MODULE_EXTENSION)
|
|||||||
execute_process(
|
execute_process(
|
||||||
COMMAND
|
COMMAND
|
||||||
"${${_Python}_EXECUTABLE}" "-c"
|
"${${_Python}_EXECUTABLE}" "-c"
|
||||||
"from distutils import sysconfig as s;print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))"
|
"import sys, importlib; s = importlib.import_module('distutils.sysconfig' if sys.version_info < (3, 10) else 'sysconfig'); print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))"
|
||||||
OUTPUT_VARIABLE _PYTHON_MODULE_EXTENSION
|
OUTPUT_VARIABLE _PYTHON_MODULE_EXTENSION
|
||||||
ERROR_VARIABLE _PYTHON_MODULE_EXTENSION_ERR
|
ERROR_VARIABLE _PYTHON_MODULE_EXTENSION_ERR
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
Loading…
Reference in New Issue
Block a user