Skip to content

Commit 16cf7ad

Browse files
committed
property_cpp_function_sh_* named specializations, as suggested by @laramiel (#5257 (comment))
1 parent 99b6572 commit 16cf7ad

File tree

1 file changed

+79
-63
lines changed

1 file changed

+79
-63
lines changed

include/pybind11/pybind11.h

Lines changed: 79 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,8 +1600,6 @@ PYBIND11_NAMESPACE_BEGIN(detail)
16001600
template <typename PM>
16011601
using must_be_member_function_pointer = enable_if_t<std::is_member_pointer<PM>::value, int>;
16021602

1603-
PYBIND11_NAMESPACE_END(detail)
1604-
16051603
// Note that property_cpp_function is intentionally in the main pybind11 namespace,
16061604
// because user-defined specializations could be useful.
16071605

@@ -1611,24 +1609,31 @@ PYBIND11_NAMESPACE_END(detail)
16111609
// WARNING: This classic implementation can lead to dangling pointers for raw pointer members.
16121610
// See test_ptr() in tests/test_class_sh_property.py
16131611
// This implementation works as-is (and safely) for smart_holder std::shared_ptr members.
1614-
template <typename T, typename D, typename SFINAE = void>
1615-
struct property_cpp_function {
1616-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1612+
template <typename T, typename D>
1613+
struct property_cpp_function_classic {
1614+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16171615
static cpp_function readonly(PM pm, const handle &hdl) {
16181616
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
16191617
}
16201618

1621-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1619+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16221620
static cpp_function read(PM pm, const handle &hdl) {
16231621
return readonly(pm, hdl);
16241622
}
16251623

1626-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1624+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16271625
static cpp_function write(PM pm, const handle &hdl) {
16281626
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
16291627
}
16301628
};
16311629

1630+
PYBIND11_NAMESPACE_END(detail)
1631+
1632+
template <typename T, typename D, typename SFINAE = void>
1633+
struct property_cpp_function : detail::property_cpp_function_classic<T, D> {};
1634+
1635+
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
1636+
16321637
PYBIND11_NAMESPACE_BEGIN(detail)
16331638

16341639
template <typename T, typename D, typename SFINAE = void>
@@ -1644,10 +1649,6 @@ struct both_t_and_d_use_type_caster_base<
16441649
std::is_base_of<type_caster_base<intrinsic_t<D>>, make_caster<D>>>::value>>
16451650
: std::true_type {};
16461651

1647-
PYBIND11_NAMESPACE_END(detail)
1648-
1649-
#ifdef PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
1650-
16511652
// BAKEIN_WIP: Rewrite comment.
16521653
// smart_holder specializations for raw pointer members.
16531654
// WARNING: Like the classic implementation, this implementation can lead to dangling pointers.
@@ -1656,22 +1657,18 @@ PYBIND11_NAMESPACE_END(detail)
16561657
// https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233
16571658
// This prevents disowning of the Python object owning the raw pointer member.
16581659
template <typename T, typename D>
1659-
struct property_cpp_function<
1660-
T,
1661-
D,
1662-
detail::enable_if_t<detail::all_of<std::is_pointer<D>,
1663-
detail::both_t_and_d_use_type_caster_base<T, D>>::value>> {
1664-
1660+
struct property_cpp_function_sh_raw_ptr_member {
16651661
using drp = typename std::remove_pointer<D>::type;
16661662

1667-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1663+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16681664
static cpp_function readonly(PM pm, const handle &hdl) {
1669-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1670-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1665+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1666+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
16711667
return cpp_function(
16721668
[pm](handle c_hdl) -> std::shared_ptr<drp> {
1673-
std::shared_ptr<T> c_sp = detail::type_caster<
1674-
std::shared_ptr<T>>::shared_ptr_with_responsible_parent(c_hdl);
1669+
std::shared_ptr<T> c_sp
1670+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
1671+
c_hdl);
16751672
D ptr = (*c_sp).*pm;
16761673
return std::shared_ptr<drp>(c_sp, ptr);
16771674
},
@@ -1680,15 +1677,15 @@ struct property_cpp_function<
16801677
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
16811678
}
16821679

1683-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1680+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16841681
static cpp_function read(PM pm, const handle &hdl) {
16851682
return readonly(pm, hdl);
16861683
}
16871684

1688-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1685+
template <typename PM, must_be_member_function_pointer<PM> = 0>
16891686
static cpp_function write(PM pm, const handle &hdl) {
1690-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1691-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1687+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1688+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
16921689
return cpp_function([pm](T &c, D value) { c.*pm = std::forward<D>(std::move(value)); },
16931690
is_method(hdl));
16941691
}
@@ -1702,23 +1699,16 @@ struct property_cpp_function<
17021699
// https://github.com/google/clif/blob/c371a6d4b28d25d53a16e6d2a6d97305fb1be25a/clif/python/instance.h#L233
17031700
// This prevents disowning of the Python object owning the member.
17041701
template <typename T, typename D>
1705-
struct property_cpp_function<T,
1706-
D,
1707-
detail::enable_if_t<detail::all_of<
1708-
detail::none_of<std::is_pointer<D>,
1709-
std::is_array<D>,
1710-
detail::is_instantiation<std::unique_ptr, D>,
1711-
detail::is_instantiation<std::shared_ptr, D>>,
1712-
detail::both_t_and_d_use_type_caster_base<T, D>>::value>> {
1713-
1714-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1702+
struct property_cpp_function_sh_member_held_by_value {
1703+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17151704
static cpp_function readonly(PM pm, const handle &hdl) {
1716-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1717-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1705+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1706+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
17181707
return cpp_function(
17191708
[pm](handle c_hdl) -> std::shared_ptr<typename std::add_const<D>::type> {
1720-
std::shared_ptr<T> c_sp = detail::type_caster<
1721-
std::shared_ptr<T>>::shared_ptr_with_responsible_parent(c_hdl);
1709+
std::shared_ptr<T> c_sp
1710+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
1711+
c_hdl);
17221712
return std::shared_ptr<typename std::add_const<D>::type>(c_sp,
17231713
&(c_sp.get()->*pm));
17241714
},
@@ -1727,25 +1717,26 @@ struct property_cpp_function<T,
17271717
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
17281718
}
17291719

1730-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1720+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17311721
static cpp_function read(PM pm, const handle &hdl) {
1732-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1733-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1722+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1723+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
17341724
return cpp_function(
17351725
[pm](handle c_hdl) -> std::shared_ptr<D> {
1736-
std::shared_ptr<T> c_sp = detail::type_caster<
1737-
std::shared_ptr<T>>::shared_ptr_with_responsible_parent(c_hdl);
1726+
std::shared_ptr<T> c_sp
1727+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
1728+
c_hdl);
17381729
return std::shared_ptr<D>(c_sp, &(c_sp.get()->*pm));
17391730
},
17401731
is_method(hdl));
17411732
}
17421733
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
17431734
}
17441735

1745-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1736+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17461737
static cpp_function write(PM pm, const handle &hdl) {
1747-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1748-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1738+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1739+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
17491740
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
17501741
}
17511742
return cpp_function([pm](T &c, const D &value) { c.*pm = value; }, is_method(hdl));
@@ -1760,41 +1751,66 @@ struct property_cpp_function<T,
17601751
// accessible as a Python object without disowning the member unique_ptr. A .def_readonly disowning
17611752
// the unique_ptr member is deemed highly prone to misunderstandings.
17621753
template <typename T, typename D>
1763-
struct property_cpp_function<
1764-
T,
1765-
D,
1766-
detail::enable_if_t<detail::all_of<
1767-
detail::is_instantiation<std::unique_ptr, D>,
1768-
detail::both_t_and_d_use_type_caster_base<T, typename D::element_type>>::value>> {
1769-
1770-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1754+
struct property_cpp_function_sh_unique_ptr_member {
1755+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17711756
static cpp_function readonly(PM, const handle &) {
1772-
static_assert(!detail::is_instantiation<std::unique_ptr, D>::value,
1757+
static_assert(!is_instantiation<std::unique_ptr, D>::value,
17731758
"def_readonly cannot be used for std::unique_ptr members.");
17741759
return cpp_function{}; // Unreachable.
17751760
}
17761761

1777-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1762+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17781763
static cpp_function read(PM pm, const handle &hdl) {
1779-
detail::type_info *tinfo = detail::get_type_info(typeid(T), /*throw_if_missing=*/true);
1780-
if (tinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
1764+
type_info *tinfo = get_type_info(typeid(T), /*throw_if_missing=*/true);
1765+
if (tinfo->holder_enum_v == holder_enum_t::smart_holder) {
17811766
return cpp_function(
17821767
[pm](handle c_hdl) -> D {
1783-
std::shared_ptr<T> c_sp = detail::type_caster<
1784-
std::shared_ptr<T>>::shared_ptr_with_responsible_parent(c_hdl);
1768+
std::shared_ptr<T> c_sp
1769+
= type_caster<std::shared_ptr<T>>::shared_ptr_with_responsible_parent(
1770+
c_hdl);
17851771
return D{std::move(c_sp.get()->*pm)};
17861772
},
17871773
is_method(hdl));
17881774
}
17891775
return cpp_function([pm](const T &c) -> const D & { return c.*pm; }, is_method(hdl));
17901776
}
17911777

1792-
template <typename PM, detail::must_be_member_function_pointer<PM> = 0>
1778+
template <typename PM, must_be_member_function_pointer<PM> = 0>
17931779
static cpp_function write(PM pm, const handle &hdl) {
17941780
return cpp_function([pm](T &c, D &&value) { c.*pm = std::move(value); }, is_method(hdl));
17951781
}
17961782
};
17971783

1784+
PYBIND11_NAMESPACE_END(detail)
1785+
1786+
template <typename T, typename D>
1787+
struct property_cpp_function<
1788+
T,
1789+
D,
1790+
detail::enable_if_t<detail::all_of<std::is_pointer<D>,
1791+
detail::both_t_and_d_use_type_caster_base<T, D>>::value>>
1792+
: detail::property_cpp_function_sh_raw_ptr_member<T, D> {};
1793+
1794+
template <typename T, typename D>
1795+
struct property_cpp_function<T,
1796+
D,
1797+
detail::enable_if_t<detail::all_of<
1798+
detail::none_of<std::is_pointer<D>,
1799+
std::is_array<D>,
1800+
detail::is_instantiation<std::unique_ptr, D>,
1801+
detail::is_instantiation<std::shared_ptr, D>>,
1802+
detail::both_t_and_d_use_type_caster_base<T, D>>::value>>
1803+
: detail::property_cpp_function_sh_member_held_by_value<T, D> {};
1804+
1805+
template <typename T, typename D>
1806+
struct property_cpp_function<
1807+
T,
1808+
D,
1809+
detail::enable_if_t<detail::all_of<
1810+
detail::is_instantiation<std::unique_ptr, D>,
1811+
detail::both_t_and_d_use_type_caster_base<T, typename D::element_type>>::value>>
1812+
: detail::property_cpp_function_sh_unique_ptr_member<T, D> {};
1813+
17981814
#endif // PYBIND11_HAVE_INTERNALS_WITH_SMART_HOLDER_SUPPORT
17991815

18001816
#if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT) \

0 commit comments

Comments
 (0)