cast: Qualify symbol usage in PYBIND11_TYPE_CASTER (#3758)

* cast: Qualify symbol usage in PYBIND11_TYPE_CASTER

Permits using macro outside of pybind11::detail

* fixup! review
This commit is contained in:
Eric Cousineau 2022-02-25 16:25:23 -05:00 committed by GitHub
parent da15bb206c
commit f495dfc433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 5 deletions

View File

@ -85,11 +85,15 @@ protected:
\ \
public: \ public: \
static constexpr auto name = py_name; \ static constexpr auto name = py_name; \
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \ template <typename T_, \
static handle cast(T_ *src, return_value_policy policy, handle parent) { \ ::pybind11::detail::enable_if_t< \
std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value, \
int> = 0> \
static ::pybind11::handle cast( \
T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \
if (!src) \ if (!src) \
return none().release(); \ return ::pybind11::none().release(); \
if (policy == return_value_policy::take_ownership) { \ if (policy == ::pybind11::return_value_policy::take_ownership) { \
auto h = cast(std::move(*src), policy, parent); \ auto h = cast(std::move(*src), policy, parent); \
delete src; \ delete src; \
return h; \ return h; \
@ -100,7 +104,7 @@ public:
operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \ operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \
operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \ operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \
template <typename T_> \ template <typename T_> \
using cast_op_type = pybind11::detail::movable_cast_op_type<T_> using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>
template <typename CharT> template <typename CharT>
using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */ using is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */

View File

@ -20,6 +20,7 @@ public:
std::string arg = "(default arg inspector 2)"; std::string arg = "(default arg inspector 2)";
}; };
class ArgAlwaysConverts {}; class ArgAlwaysConverts {};
namespace pybind11 { namespace pybind11 {
namespace detail { namespace detail {
template <> template <>
@ -105,6 +106,34 @@ struct type_caster<DestructionTester> {
} // namespace detail } // namespace detail
} // namespace pybind11 } // namespace pybind11
// Define type caster outside of `pybind11::detail` and then alias it.
namespace other_lib {
struct MyType {};
// Corrupt `py` shorthand alias for surrounding context.
namespace py {}
// Corrupt unqualified relative `pybind11` namespace.
namespace pybind11 {}
// Correct alias.
namespace py_ = ::pybind11;
// Define caster. This is effectively no-op, we only ensure it compiles and we
// don't have any symbol collision when using macro mixin.
struct my_caster {
PYBIND11_TYPE_CASTER(MyType, py_::detail::const_name("MyType"));
bool load(py_::handle, bool) { return true; }
static py_::handle cast(const MyType &, py_::return_value_policy, py_::handle) {
return py_::bool_(true).release();
}
};
} // namespace other_lib
// Effectively "alias" it into correct namespace (via inheritance).
namespace pybind11 {
namespace detail {
template <>
struct type_caster<other_lib::MyType> : public other_lib::my_caster {};
} // namespace detail
} // namespace pybind11
TEST_SUBMODULE(custom_type_casters, m) { TEST_SUBMODULE(custom_type_casters, m) {
// test_custom_type_casters // test_custom_type_casters
@ -175,4 +204,6 @@ TEST_SUBMODULE(custom_type_casters, m) {
m.def("destruction_tester_cstats", m.def("destruction_tester_cstats",
&ConstructorStats::get<DestructionTester>, &ConstructorStats::get<DestructionTester>,
py::return_value_policy::reference); py::return_value_policy::reference);
m.def("other_lib_type", [](other_lib::MyType x) { return x; });
} }

View File

@ -114,3 +114,7 @@ def test_custom_caster_destruction():
# Make sure we still only have the original object (from ..._no_destroy()) alive: # Make sure we still only have the original object (from ..._no_destroy()) alive:
assert cstats.alive() == 1 assert cstats.alive() == 1
def test_custom_caster_other_lib():
assert m.other_lib_type(True)