mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-21 13:30:26 +00:00
Resolve empty statement warning when using PYBIND11_OVERLOAD_PURE_NAME and PYBIND11_OVERLOAD_PURE (#2325)
* Wrap PYBIND11_OVERLOAD_NAME and PYBIND11_OVERLOAD_PURE_NAME in do { ... } while (false), and resolve trailing semicolon
* Deprecate PYBIND11_OVERLOAD_* and get_overload in favor of PYBIND11_OVERRIDE_* and get_override
* Correct erroneous usage of 'overload' instead of 'override' in the implementation and internals
* Fix tests to use non-deprecated PYBIND11_OVERRIDE_* macros
* Update docs to use override instead of overload where appropriate, and add warning about deprecated aliases
* Add semicolons to deprecated PYBIND11_OVERLOAD macros to match original behavior
* Remove deprecation of PYBIND11_OVERLOAD_* macros and get_overload
* Add note to changelog and upgrade guide
This commit is contained in:
@@ -1797,16 +1797,16 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
template <typename T, enable_if_t<!is_pyobject<T>::value, int>>
|
||||
object object_or_cast(T &&o) { return pybind11::cast(std::forward<T>(o)); }
|
||||
|
||||
struct overload_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the OVERLOAD_INT macro
|
||||
template <typename ret_type> using overload_caster_t = conditional_t<
|
||||
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, overload_unused>;
|
||||
struct override_unused {}; // Placeholder type for the unneeded (and dead code) static variable in the PYBIND11_OVERRIDE_OVERRIDE macro
|
||||
template <typename ret_type> using override_caster_t = conditional_t<
|
||||
cast_is_temporary_value_reference<ret_type>::value, make_caster<ret_type>, override_unused>;
|
||||
|
||||
// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then
|
||||
// store the result in the given variable. For other types, this is a no-op.
|
||||
template <typename T> enable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o, make_caster<T> &caster) {
|
||||
return cast_op<T>(load_type(caster, o));
|
||||
}
|
||||
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, overload_unused &) {
|
||||
template <typename T> enable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&, override_unused &) {
|
||||
pybind11_fail("Internal error: cast_ref fallback invoked"); }
|
||||
|
||||
// Trampoline use: Having a pybind11::cast with an invalid reference type is going to static_assert, even
|
||||
@@ -2222,7 +2222,7 @@ type type::of() {
|
||||
}}
|
||||
|
||||
/// Lets you pass a type containing a `,` through a macro parameter without needing a separate
|
||||
/// typedef, e.g.: `PYBIND11_OVERLOAD(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
|
||||
/// typedef, e.g.: `PYBIND11_OVERRIDE(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`
|
||||
#define PYBIND11_TYPE(...) __VA_ARGS__
|
||||
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
||||
@@ -82,10 +82,10 @@ struct type_equal_to {
|
||||
template <typename value_type>
|
||||
using type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;
|
||||
|
||||
struct overload_hash {
|
||||
struct override_hash {
|
||||
inline size_t operator()(const std::pair<const PyObject *, const char *>& v) const {
|
||||
size_t value = std::hash<const void *>()(v.first);
|
||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
||||
value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value<<6) + (value>>2);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
@@ -97,7 +97,7 @@ struct internals {
|
||||
type_map<type_info *> registered_types_cpp; // std::type_index -> pybind11's type information
|
||||
std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py; // PyTypeObject* -> base type_info(s)
|
||||
std::unordered_multimap<const void *, instance*> registered_instances; // void * -> instance*
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, overload_hash> inactive_overload_cache;
|
||||
std::unordered_set<std::pair<const PyObject *, const char *>, override_hash> inactive_override_cache;
|
||||
type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;
|
||||
std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;
|
||||
std::forward_list<void (*) (std::exception_ptr)> registered_exception_translators;
|
||||
|
||||
@@ -2110,21 +2110,22 @@ error_already_set::~error_already_set() {
|
||||
}
|
||||
}
|
||||
|
||||
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
|
||||
handle self = detail::get_object_handle(this_ptr, this_type);
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
inline function get_type_override(const void *this_ptr, const type_info *this_type, const char *name) {
|
||||
handle self = get_object_handle(this_ptr, this_type);
|
||||
if (!self)
|
||||
return function();
|
||||
handle type = self.get_type();
|
||||
auto key = std::make_pair(type.ptr(), name);
|
||||
|
||||
/* Cache functions that aren't overloaded in Python to avoid
|
||||
/* Cache functions that aren't overridden in Python to avoid
|
||||
many costly Python dictionary lookups below */
|
||||
auto &cache = detail::get_internals().inactive_overload_cache;
|
||||
auto &cache = get_internals().inactive_override_cache;
|
||||
if (cache.find(key) != cache.end())
|
||||
return function();
|
||||
|
||||
function overload = getattr(self, name, function());
|
||||
if (overload.is_cpp_function()) {
|
||||
function override = getattr(self, name, function());
|
||||
if (override.is_cpp_function()) {
|
||||
cache.insert(key);
|
||||
return function();
|
||||
}
|
||||
@@ -2164,34 +2165,36 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
|
||||
Py_DECREF(result);
|
||||
#endif
|
||||
|
||||
return overload;
|
||||
return override;
|
||||
}
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
/** \rst
|
||||
Try to retrieve a python method by the provided name from the instance pointed to by the this_ptr.
|
||||
|
||||
:this_ptr: The pointer to the object the overload should be retrieved for. This should be the first
|
||||
non-trampoline class encountered in the inheritance chain.
|
||||
:name: The name of the overloaded Python method to retrieve.
|
||||
:this_ptr: The pointer to the object the overriden method should be retrieved for. This should be
|
||||
the first non-trampoline class encountered in the inheritance chain.
|
||||
:name: The name of the overridden Python method to retrieve.
|
||||
:return: The Python method by this name from the object or an empty function wrapper.
|
||||
\endrst */
|
||||
template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
template <class T> function get_override(const T *this_ptr, const char *name) {
|
||||
auto tinfo = detail::get_type_info(typeid(T));
|
||||
return tinfo ? get_type_overload(this_ptr, tinfo, name) : function();
|
||||
return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();
|
||||
}
|
||||
|
||||
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \
|
||||
#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...) \
|
||||
do { \
|
||||
pybind11::gil_scoped_acquire gil; \
|
||||
pybind11::function overload = pybind11::get_overload(static_cast<const cname *>(this), name); \
|
||||
if (overload) { \
|
||||
auto o = overload(__VA_ARGS__); \
|
||||
pybind11::function override = pybind11::get_override(static_cast<const cname *>(this), name); \
|
||||
if (override) { \
|
||||
auto o = override(__VA_ARGS__); \
|
||||
if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) { \
|
||||
static pybind11::detail::overload_caster_t<ret_type> caster; \
|
||||
static pybind11::detail::override_caster_t<ret_type> caster; \
|
||||
return pybind11::detail::cast_ref<ret_type>(std::move(o), caster); \
|
||||
} \
|
||||
else return pybind11::detail::cast_safe<ret_type>(std::move(o)); \
|
||||
} \
|
||||
}
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro to populate the virtual method in the trampoline class. This macro tries to look up a method named 'fn'
|
||||
@@ -2202,7 +2205,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
.. code-block:: cpp
|
||||
|
||||
std::string toString() override {
|
||||
PYBIND11_OVERLOAD_NAME(
|
||||
PYBIND11_OVERRIDE_NAME(
|
||||
std::string, // Return type (ret_type)
|
||||
Animal, // Parent class (cname)
|
||||
"__str__", // Name of method in Python (name)
|
||||
@@ -2210,17 +2213,21 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
);
|
||||
}
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
|
||||
return cname::fn(__VA_ARGS__)
|
||||
#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...) \
|
||||
do { \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
|
||||
return cname::fn(__VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD_NAME`, except that it
|
||||
throws if no overload can be found.
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE_NAME`, except that it
|
||||
throws if no override can be found.
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERLOAD_INT(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__) \
|
||||
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\"");
|
||||
#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
do { \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \
|
||||
pybind11::pybind11_fail("Tried to call pure virtual function \"" PYBIND11_STRINGIFY(cname) "::" name "\""); \
|
||||
} while (false)
|
||||
|
||||
/** \rst
|
||||
Macro to populate the virtual method in the trampoline class. This macro tries to look up the method
|
||||
@@ -2237,7 +2244,7 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
|
||||
// Trampoline (need one for each virtual function)
|
||||
std::string go(int n_times) override {
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
PYBIND11_OVERRIDE_PURE(
|
||||
std::string, // Return type (ret_type)
|
||||
Animal, // Parent class (cname)
|
||||
go, // Name of function in C++ (must match Python name) (fn)
|
||||
@@ -2246,15 +2253,39 @@ template <class T> function get_overload(const T *this_ptr, const char *name) {
|
||||
}
|
||||
};
|
||||
\endrst */
|
||||
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERLOAD_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
|
||||
/** \rst
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERLOAD`, except that it throws
|
||||
if no overload can be found.
|
||||
Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE`, except that it throws
|
||||
if no override can be found.
|
||||
\endrst */
|
||||
#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
|
||||
|
||||
// Deprecated versions
|
||||
|
||||
PYBIND11_DEPRECATED("get_type_overload has been deprecated")
|
||||
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
|
||||
return detail::get_type_override(this_ptr, this_type, name);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline function get_overload(const T *this_ptr, const char *name) {
|
||||
return get_override(this_ptr, name);
|
||||
}
|
||||
|
||||
#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) \
|
||||
PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...) \
|
||||
PYBIND11_OVERRIDE_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);
|
||||
#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERRIDE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__)
|
||||
#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...) \
|
||||
PYBIND11_OVERLOAD_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)
|
||||
PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);
|
||||
|
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user