头文件
#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
namespace py = pybind11;
PYBIND11_MODULE
PYBIND11_MODULE(_k2, m) {
m.doc() = "pybind11 binding of k2";
PybindVersion(m);
PybindTorch(m);
}
#define PYBIND11\_CONCAT(first, second) first##second
#if defined(PYBIND11\_CPP17)
# define PYBIND11\_MAYBE\_UNUSED [[maybe\_unused]]
#elif defined(\_MSC\_VER) && !defined(\_\_clang\_\_)
# define PYBIND11\_MAYBE\_UNUSED
#else
# define PYBIND11\_MAYBE\_UNUSED \_\_attribute\_\_((\_\_unused\_\_))
#endif
#if !defined(PYBIND11\_EXPORT)
# if defined(WIN32) || defined(\_WIN32)
# define PYBIND11\_EXPORT \_\_declspec(dllexport)
# else
# define PYBIND11\_EXPORT \_\_attribute\_\_((visibility("default")))
# endif
#endif
// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.
// See comment for PYBIND11\_MODULE below for why this is marked "maybe unused".
#define PYBIND11\_PLUGIN\_IMPL(name) \
extern "C" PYBIND11\_MAYBE\_UNUSED PYBIND11\_EXPORT PyObject *PyInit\_##name(); \
extern "C" PYBIND11\_EXPORT PyObject *PyInit\_##name()
// pybind11/detail/common.h
/** \rst
This macro creates the entry point that will be invoked when the Python interpreter
imports an extension module. The module name is given as the first argument and it
should not be in quotes. The second macro argument defines a variable of type
`py::module\_` which can be used to initialize the module.
The entry point is marked as "maybe unused" to aid dead-code detection analysis:
since the entry point is typically only looked up at runtime and not referenced
during translation, it would otherwise appear as unused ("dead") code.
.. code-block:: cpp
PYBIND11\_MODULE(example, m) {
m.doc() = "pybind11 example module";
// Add bindings here
m.def("foo", []() {
return "Hello, World!";
});
}
\endrst */
#define PYBIND11\_MODULE(name, variable) \
static ::pybind11::module\_::module\_def PYBIND11\_CONCAT(pybind11\_module\_def\_, name) \
PYBIND11\_MAYBE\_UNUSED; \
PYBIND11\_MAYBE\_UNUSED \
static void PYBIND11\_CONCAT(pybind11\_init\_, name)(::pybind11::module\_ &); \
PYBIND11\_PLUGIN\_IMPL(name) { \
PYBIND11\_CHECK\_PYTHON\_VERSION \
PYBIND11\_ENSURE\_INTERNALS\_READY \
auto m = ::pybind11::module\_::create\_extension\_module( \
PYBIND11\_TOSTRING(name), nullptr, &PYBIND11\_CONCAT(pybind11\_module\_def\_, name)); \
try { \
PYBIND11\_CONCAT(pybind11\_init\_, name)(m); \
return m.ptr(); \
} \
PYBIND11\_CATCH\_INIT\_EXCEPTIONS \
} \
void PYBIND11\_CONCAT(pybind11\_init\_, name)(::pybind11::module\_ & (variable))
- 定义module_def对象。
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name);
- 声明init方法。
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &);
- 定义
PyInit_##name()
方法。创建module,并调用init方法初始化,返回PyObject*
。 - 定义init方法。
void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable)) {...}
Building C and C++ Extensions
初始化函数有如下签名:
PyObject *PyInit_<modulename>(void)
它要么返回一个完全初始化的module,要么返回一个PyModuleDef
实例。
对于只有ascii名称的模块,函数必须命名为PyInit_<modulename>
,其中<modulename>
被模块名称替换。当使用Multi-phase初始化时,允许使用非ascii模块名。在本例中,初始化函数名为PyInitU_<modulename>
,其中<modulename>
使用Python的punycode编码,连字符被下划线替换。
Initializing C modules
https://docs.python.org/3/c-api/module.html#initializing-c-modules
模块对象通常由扩展模块(导出初始化函数的共享库)或编译模块(其中初始化函数是使用PyImport_AppendInittab()
添加的)创建。
初始化函数可以将模块定义实例传递给PyModule_Create()
,并返回结果模块对象,或者通过返回定义结构本身来请求“多阶段初始化”。
py::module
// pybind11/pybind11.h
// When inside a namespace (or anywhere as long as it's not the first item on a line),
// C++20 allows "module" to be used. This is provided for backward compatibility, and for
// simplicity, if someone wants to use py::module for example, that is perfectly safe.
using module = module_;
py::module_
// pybind11/pybind11.h
/// Wrapper for Python extension modules
class module\_ : public object {
public:
PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)
/// Create a new top-level Python module with the given name and docstring
PYBIND11_DEPRECATED("Use PYBIND11\_MODULE or module\_::create\_extension\_module instead")
explicit module\_(const char *name, const char *doc = nullptr) {
*this = create_extension_module(name, doc, new PyModuleDef());
}
/** \rst
Create Python binding for a new function within the module scope. ``Func``
can be a plain C++ function, a function pointer, or a lambda function. For
details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
\endrst */
template <typename Func, typename... Extra>
module\_ &def(const char *name\_, Func &&f, const Extra &...extra) {
cpp\_function func(std::forward<Func>(f),
name(name\_),
scope(*this),
sibling(getattr(*this, name\_, none())),
extra...);
// NB: allow overwriting here because cpp\_function sets up a chain with the intention of
// overwriting (and has already checked internally that it isn't overwriting
// non-functions).
add_object(name_, func, true /* overwrite */);
return *this;
}
/** \rst
Create and return a new Python submodule with the given name and docstring.
This also works recursively, i.e.
.. code-block:: cpp
py::module\_ m("example", "pybind11 example plugin");
py::module\_ m2 = m.def\_submodule("sub", "A submodule of 'example'");
py::module\_ m3 = m2.def\_submodule("subsub", "A submodule of 'example.sub'");
\endrst */
module\_ def\_submodule(const char *name, const char *doc = nullptr) {
const char *this_name = PyModule_GetName(m_ptr);
if (this_name == nullptr) {
throw error_already_set();
}
std::string full_name = std::string(this_name) + '.' + name;
handle submodule = PyImport_AddModule(full_name.c_str());
if (!submodule) {
throw error_already_set();
}
auto result = reinterpret_borrow<module_>(submodule);
if (doc && options::show_user_defined_docstrings()) {
result.attr("\_\_doc\_\_") = pybind11::str(doc);
}
attr(name) = result;
return result;
}
/// Import and return a module or throws `error\_already\_set`.
static module\_ import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
if (!obj) {
throw error_already_set();
}
return reinterpret_steal<module_>(obj);
}
/// Reload the module or throws `error\_already\_set`.
void reload() {
PyObject *obj = PyImport_ReloadModule(ptr());
if (!obj) {
throw error_already_set();
}
*this = reinterpret_steal<module_>(obj);
}
/** \rst
Adds an object to the module using the given name. Throws if an object with the given name
already exists.
``overwrite`` should almost always be false: attempting to overwrite objects that pybind11
has established will, in most cases, break things.
\endrst */
PYBIND11\_NOINLINE void add\_object(const char *name, handle obj, bool overwrite = false) {
if (!overwrite && hasattr(*this, name)) {
pybind11_fail(
"Error during initialization: multiple incompatible definitions with name \""
+ std::string(name) + "\"");
}
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
}
using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)?
/** \rst
Create a new top-level module that can be used as the main module of a C extension.
``def`` should point to a statically allocated module\_def.
\endrst */
static module\_ create\_extension\_module(const char *name, const char *doc, module\_def *def) {
// module\_def is PyModuleDef
// Placement new (not an allocation).
def = new (def)
PyModuleDef{/* m\_base */ PyModuleDef_HEAD_INIT,
/* m\_name */ name,
/* m\_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
/* m\_size */ -1,
/* m\_methods */ nullptr,
/* m\_slots */ nullptr,
/* m\_traverse */ nullptr,
/* m\_clear */ nullptr,
/* m\_free */ nullptr};
auto *m = PyModule_Create(def);
if (m == nullptr) {
if (PyErr_Occurred()) {
throw error_already_set();
}
pybind11_fail("Internal error in module\_::create\_extension\_module()");
}
// TODO: Should be reinterpret\_steal for Python 3, but Python also steals it again when
// returned from PyInit\_...
// For Python 2, reinterpret\_borrow was correct.
return reinterpret_borrow<module_>(m);
}
};
// include/python3.9/moduleobject.h
typedef struct PyModuleDef{
PyModuleDef_Base m_base;
const char* m_name;
const char* m_doc;
Py_ssize_t m_size;
PyMethodDef *m_methods;
struct PyModuleDef\_Slot* m\_slots;
traverseproc m_traverse;
inquiry m_clear;
freefunc m_free;
} PyModuleDef;
// include/python3.9/moduleobject.h
PyAPI_DATA(PyTypeObject) PyModule_Type;
#define PyModule\_Check(op) PyObject\_TypeCheck(op, &PyModule\_Type)
// include/python3.9/import.h
PyAPI_FUNC(PyObject *) PyImport_AddModule(
const char *name /* UTF-8 encoded string */
);
PyAPI_FUNC(PyObject *) PyImport_ImportModule(
const char *name /* UTF-8 encoded string */
);
py::object
py::object 类继承自 py::handle 并添加自动引用计数功能。
// pybind11/pytypes.h
/** \rst
Holds a reference to a Python object (with reference counting)
Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
optionally increases the object's reference count upon construction, and it
*always* decreases the reference count when the `object` instance goes out of
scope and is destructed. When using `object` instances consistently, it is much
easier to get reference counting right at the first attempt.
\endrst */
class object : public handle {
public:
object() = default;
PYBIND11_DEPRECATED("Use reinterpret\_borrow<object>() or reinterpret\_steal<object>()")
object(handle h, bool is_borrowed) : handle(h) {
if (is_borrowed) {
inc_ref();
}
}
/// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); }
/// Move constructor; steals the object from ``other`` and preserves its reference count
object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }
/// Destructor; automatically calls `handle::dec\_ref()`
~object() { dec_ref(); }
/** \rst
Resets the internal pointer to ``nullptr`` without decreasing the
object's reference count. The function returns a raw handle to the original
Python object.
\endrst */
handle release() {
PyObject *tmp = m_ptr;
m_ptr = nullptr;
return handle(tmp);
}
object &operator=(const object &other) {
// Skip inc\_ref and dec\_ref if both objects are the same
if (!this->is(other)) {
other.inc_ref();
// Use temporary variable to ensure `*this` remains valid while
// `Py\_XDECREF` executes, in case `*this` is accessible from Python.
handle temp(m\_ptr);
m_ptr = other.m_ptr;
temp.dec_ref();
}
return *this;
}
object &operator=(object &&other) noexcept {
if (this != &other) {
handle temp(m_ptr);
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
temp.dec_ref();
}
return *this;
}
#define PYBIND11\_INPLACE\_OP(iop) \
object iop(object\_api const &other) { return operator=(handle::iop(other)); }
PYBIND11_INPLACE_OP(operator+=)
PYBIND11_INPLACE_OP(operator-=)
PYBIND11_INPLACE_OP(operator*=)
PYBIND11_INPLACE_OP(operator/=)
PYBIND11_INPLACE_OP(operator|=)
PYBIND11_INPLACE_OP(operator&=)
PYBIND11_INPLACE_OP(operator^=)
PYBIND11_INPLACE_OP(operator<<=)
PYBIND11_INPLACE_OP(operator>>=)
#undef PYBIND11\_INPLACE\_OP
// Calling cast() on an object lvalue just copies (via handle::cast)
template <typename T>
T cast() const &;
// Calling on an object rvalue does a move, if needed and/or possible
template <typename T>
T cast() &&;
protected:
// Tags for choosing constructors from raw PyObject *
struct borrowed\_t {};
struct stolen\_t {};
/// @cond BROKEN
template <typename T>
friend T reinterpret\_borrow(handle);
template <typename T>
friend T reinterpret\_steal(handle);
/// @endcond
public:
// Only accessible from derived classes and the reinterpret\_* functions
object(handle h, borrowed\_t) : handle(h) { inc_ref(); }
object(handle h, stolen\_t) : handle(h) {}
};
py::handle
持有 PyObject *m_ptr = nullptr;
对象。
py::handle 类是对任意Python对象(即 Python C API中的 PyObject* )。它不执行任何自动引用,并且仅仅提供了一个基本的c++接口来处理各种Python API函数。
// pybind11/pytypes.h
/** \rst
Holds a reference to a Python object (no reference counting)
The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
``PyObject *`` in Python's C API). It does not perform any automatic reference
counting and merely provides a basic C++ interface to various Python API functions.
.. seealso::
The `object` class inherits from `handle` and adds automatic reference
counting features.
\endrst */
class handle : public detail::object_api<handle> {
public:
/// The default constructor creates a handle with a ``nullptr``-valued pointer
handle() = default;
/// Enable implicit conversion from ``PyObject *`` and ``nullptr``.
/// Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``.
template <typename T,
detail::enable\_if\_t<detail::is\_pyobj\_ptr\_or\_nullptr\_t<T>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
handle(T ptr) : m_ptr(ptr) {}
/// Enable implicit conversion through ``T::operator PyObject *()``.
template <
typename T,
detail::enable\_if\_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,
detail::is\_pyobj\_ptr\_or\_nullptr\_t<T>>,
std::is_convertible<T, PyObject *>>::value,
int>
= 0>
// NOLINTNEXTLINE(google-explicit-constructor)
handle(T &obj) : m_ptr(obj) {}
/// Return the underlying ``PyObject *`` pointer
PyObject *ptr() const { return m_ptr; }
PyObject *&ptr() { return m_ptr; }
/** \rst
Manually increase the reference count of the Python object. Usually, it is
preferable to use the `object` class which derives from `handle` and calls
this function automatically. Returns a reference to itself.
\endrst */
const handle &inc\_ref() const & {
#ifdef PYBIND11\_HANDLE\_REF\_DEBUG
inc_ref_counter(1);
#endif
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF
if (m_ptr != nullptr && !PyGILState_Check()) {
throw_gilstate_error("pybind11::handle::inc\_ref()");
}
#endif
Py_XINCREF(m_ptr);
return *this;
}
/** \rst
Manually decrease the reference count of the Python object. Usually, it is
preferable to use the `object` class which derives from `handle` and calls
this function automatically. Returns a reference to itself.
\endrst */
const handle &dec\_ref() const & {
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF
if (m_ptr != nullptr && !PyGILState_Check()) {
throw_gilstate_error("pybind11::handle::dec\_ref()");
}
#endif
Py_XDECREF(m_ptr);
return *this;
}
/** \rst
Attempt to cast the Python object into the given C++ type. A `cast\_error`
will be throw upon failure.
\endrst */
template <typename T>
T cast() const;
/// Return ``true`` when the `handle` wraps a valid Python object
explicit operator bool() const { return m_ptr != nullptr; }
/** \rst
Deprecated: Check that the underlying pointers are the same.
Equivalent to ``obj1 is obj2`` in Python.
\endrst */
PYBIND11_DEPRECATED("Use obj1.is(obj2) instead")
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
PYBIND11_DEPRECATED("Use !obj1.is(obj2) instead")
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
bool check() const { return m_ptr != nullptr; }
protected:
PyObject *m_ptr = nullptr;
private:
#ifdef PYBIND11\_ASSERT\_GIL\_HELD\_INCREF\_DECREF
void throw\_gilstate\_error(const std::string &function\_name) const {
fprintf(
stderr,
"%s is being called while the GIL is either not held or invalid. Please see "
"https://pybind11.readthedocs.io/en/stable/advanced/"
"misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\n",
function_name.c_str());
fflush(stderr);
if (Py_TYPE(m_ptr)->tp_name != nullptr) {
fprintf(stderr,
"The failing %s call was triggered on a %s object.\n",
function_name.c_str(),
Py_TYPE(m_ptr)->tp_name);
fflush(stderr);
}
throw std::runtime_error(function_name + " PyGILState\_Check() failure.");
}
#endif
#ifdef PYBIND11\_HANDLE\_REF\_DEBUG
static std::size\_t inc\_ref\_counter(std::size\_t add) {
thread\_local std::size\_t counter = 0;
counter += add;
return counter;
}
public:
static std::size\_t inc\_ref\_counter() { return inc_ref_counter(0); }
#endif
};
py::object_api
// pybind11/pytypes.h
/// Tag and check to identify a class which implements the Python object API
class pyobject\_tag {};
template <typename T>
using is_pyobject = std::is_base_of<pyobject_tag, remove\_reference\_t<T>>;
template <typename T>
using is\_pyobj\_ptr\_or\_nullptr\_t = detail::any_of<std::is_same<T, PyObject *>,
std::is_same<T, PyObject *const>,
std::is_same<T, std::nullptr\_t>>;
// pybind11/pytypes.h
/** \rst
A mixin class which adds common functions to `handle`, `object` and various accessors.
The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
\endrst */
template <typename Derived>
class object\_api : public pyobject_tag {
const Derived &derived() const { return static\_cast<const Derived &>(*this); }
public:
/** \rst
Return an iterator equivalent to calling ``iter()`` in Python. The object
must be a collection which supports the iteration protocol.
\endrst */
iterator begin() const;
/// Return a sentinel which ends iteration.
iterator end() const;
/** \rst
Return an internal functor to invoke the object's sequence protocol. Casting
the returned ``detail::item\_accessor`` instance to a `handle` or `object`
subclass causes a corresponding call to ``\_\_getitem\_\_``. Assigning a `handle`
or `object` subclass causes a call to ``\_\_setitem\_\_``.
\endrst */
item_accessor operator[](handle key) const;
/// See above (the only difference is that the key's reference is stolen)
item_accessor operator[](object &&key) const;
/// See above (the only difference is that the key is provided as a string literal)
item_accessor operator[](const char *key) const;
/** \rst
Return an internal functor to access the object's attributes. Casting the
returned ``detail::obj\_attr\_accessor`` instance to a `handle` or `object`
subclass causes a corresponding call to ``getattr``. Assigning a `handle`
or `object` subclass causes a call to ``setattr``.
\endrst */
obj\_attr\_accessor attr(handle key) const;
/// See above (the only difference is that the key's reference is stolen)
obj\_attr\_accessor attr(object &&key) const;
/// See above (the only difference is that the key is provided as a string literal)
str\_attr\_accessor attr(const char *key) const;
/** \rst
Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
or ``list`` for a function call. Applying another * to the result yields
** unpacking, e.g. to unpack a dict as function keyword arguments.
See :ref:`calling\_python\_functions`.
\endrst */
args_proxy operator*() const;
/// Check if the given item is contained within this object, i.e. ``item in obj``.
template <typename T>
bool contains(T &&item) const;
/** \rst
Assuming the Python object is a function or implements the ``\_\_call\_\_``
protocol, ``operator()`` invokes the underlying function, passing an
arbitrary set of parameters. The result is returned as a `object` and
may need to be converted back into a Python object using `handle::cast()`.
When some of the arguments cannot be converted to Python objects, the
function will throw a `cast\_error` exception. When the Python function
call fails, a `error\_already\_set` exception is thrown.
\endrst */
template <return_value_policy policy = return_value_policy::automatic_reference,
typename... Args>
object operator()(Args &&...args) const;
template <return_value_policy policy = return_value_policy::automatic_reference,
typename... Args>
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
object call(Args &&...args) const;
/// Equivalent to ``obj is other`` in Python.
bool is(object\_api const &other) const { return derived().ptr() == other.derived().ptr(); }
/// Equivalent to ``obj is None`` in Python.
bool is\_none() const { return derived().ptr() == Py_None; }
/// Equivalent to obj == other in Python
bool equal(object\_api const &other) const { return rich_compare(other, Py_EQ); }
bool not\_equal(object\_api const &other) const { return rich_compare(other, Py_NE); }
bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }
bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }
bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }
bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }
object operator-() const;
object operator~() const;
object operator+(object_api const &other) const;
object operator+=(object_api const &other);
object operator-(object_api const &other) const;
object operator-=(object_api const &other);
object operator*(object_api const &other) const;
object operator*=(object_api const &other);
object operator/(object_api const &other) const;
object operator/=(object_api const &other);
object operator|(object_api const &other) const;
object operator|=(object_api const &other);
object operator&(object_api const &other) const;
object operator&=(object_api const &other);
object operator^(object_api const &other) const;
object operator^=(object_api const &other);
object operator<<(object_api const &other) const;
object operator<<=(object_api const &other);
object operator>>(object_api const &other) const;
object operator>>=(object_api const &other);
PYBIND11_DEPRECATED("Use py::str(obj) instead")
pybind11::str str() const;
/// Get or set the object's docstring, i.e. ``obj.\_\_doc\_\_``.
str\_attr\_accessor doc() const;
/// Return the object's current reference count
int ref\_count() const { return static\_cast<int>(Py_REFCNT(derived().ptr())); }
// TODO PYBIND11\_DEPRECATED(
// "Call py::type::handle\_of(h) or py::type::of(h) instead of h.get\_type()")
handle get\_type() const;
private:
bool rich\_compare(object\_api const &other, int value) const;
};
py::cpp_function
// pybind11/pybind11.h
// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
class cpp\_function : public function {
public:
cpp_function() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(std::nullptr\_t) {}
/// Construct a cpp\_function from a vanilla function pointer
template <typename Return, typename... Args, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (*f)(Args...), const Extra &...extra) {
initialize(f, f, extra...);
}
/// Construct a cpp\_function from a lambda function (possibly with internal state)
template <typename Func,
typename... Extra,
typename = detail::enable\_if\_t<detail::is_lambda<Func>::value>>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Func &&f, const Extra &...extra) {
initialize(
std::forward<Func>(f), (detail::function\_signature\_t<Func> *) nullptr, extra...);
}
/// Construct a cpp\_function from a class method (non-const, no ref-qualifier)
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...), const Extra &...extra) {
initialize(
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp\_function from a class method (non-const, lvalue ref-qualifier)
/// A copy of the overload for non-const functions without explicit ref-qualifier
/// but with an added `&`.
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...) &, const Extra &...extra) {
initialize(
[f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp\_function from a class method (const, no ref-qualifier)
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...) const, const Extra &...extra) {
initialize([f](const Class *c,
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(const Class *, Arg...)) nullptr,
extra...);
}
/// Construct a cpp\_function from a class method (const, lvalue ref-qualifier)
/// A copy of the overload for const functions without explicit ref-qualifier
/// but with an added `&`.
template <typename Return, typename Class, typename... Arg, typename... Extra>
// NOLINTNEXTLINE(google-explicit-constructor)
cpp_function(Return (Class::*f)(Arg...) const &, const Extra &...extra) {
initialize([f](const Class *c,
Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },
(Return(*)(const Class *, Arg...)) nullptr,
extra...);
}
/// Return the function name
object name() const { return attr("\_\_name\_\_"); }
...
};
py::function
// pybind11/pytypes.h
class function : public object {
public:
PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)
handle cpp\_function() const {
handle fun = detail::get_function(m_ptr);
if (fun && PyCFunction_Check(fun.ptr())) {
return fun;
}
return handle();
}
bool is\_cpp\_function() const { return (bool) cpp_function(); }
};
// python3.9/object.h
PyAPI_FUNC(int) PyCallable_Check(PyObject *);
// pybind11/pytypes.h
inline handle get\_function(handle value) {
if (value) {
if (PyInstanceMethod_Check(value.ptr())) {
value = PyInstanceMethod_GET_FUNCTION(value.ptr());
} else if (PyMethod_Check(value.ptr())) {
value = PyMethod_GET_FUNCTION(value.ptr());
}
}
return value;
}
// python3.9/classobject.h
PyAPI_DATA(PyTypeObject) PyMethod_Type;
#define PyMethod\_Check(op) Py\_IS\_TYPE(op, &PyMethod\_Type)
PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type;
#define PyInstanceMethod\_Check(op) Py\_IS\_TYPE(op, &PyInstanceMethod\_Type)
参考文献
- https://en.cppreference.com/w/cpp/types/remove\_reference
- https://en.cppreference.com/w/cpp/types/is\_base\_of