@@ -1600,8 +1600,6 @@ PYBIND11_NAMESPACE_BEGIN(detail)
16001600template <typename PM>
16011601using 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+
16321637PYBIND11_NAMESPACE_BEGIN (detail)
16331638
16341639template <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.
16581659template <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.
17041701template <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.
17621753template <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