From f2004937161413946e575885d98395a9dfa9e6fa Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Fri, 25 Nov 2016 07:06:18 -0500 Subject: [PATCH] Fixed stl casters to use the appropriate type_caster cast_op_type (#529) stl casters were using a value cast to (Value) or (Key), but that isn't always appropriate. This changes it to use the appropriate value converter's cast_op_type. --- include/pybind11/stl.h | 31 +++++++++++++++---------------- tests/test_issues.cpp | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index c1ed0f97..f806a11a 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -53,7 +53,7 @@ template struct set_caster { for (auto entry : s) { if (!conv.load(entry, convert)) return false; - value.insert((Key) conv); + value.insert(conv.operator typename key_conv::template cast_op_type()); } return true; } @@ -87,7 +87,9 @@ template struct map_caster { if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) return false; - value.emplace((Key) kconv, (Value) vconv); + value.emplace( + kconv.operator typename key_conv::template cast_op_type(), + vconv.operator typename value_conv::template cast_op_type()); } return true; } @@ -121,7 +123,7 @@ template struct list_caster { for (auto it : s) { if (!conv.load(it, convert)) return false; - value.push_back((Value) conv); + value.push_back(conv.operator typename value_conv::template cast_op_type()); } return true; } @@ -167,7 +169,7 @@ template struct type_caster> for (auto it : l) { if (!conv.load(it, convert)) return false; - value[ctr++] = (Type) conv; + value[ctr++] = conv.operator typename value_conv::template cast_op_type(); } return true; } @@ -200,13 +202,12 @@ template struct optional_caster { - using value_type = typename intrinsic_type::type; - using caster_type = type_caster; + using value_conv = make_caster; static handle cast(const T& src, return_value_policy policy, handle parent) { if (!src) return none().inc_ref(); - return caster_type::cast(*src, policy, parent); + return value_conv::cast(*src, policy, parent); } bool load(handle src, bool convert) { @@ -215,18 +216,16 @@ template struct optional_caster { } else if (src.is_none()) { value = {}; // nullopt return true; - } else if (!inner.load(src, convert)) { - return false; - } else { - value.emplace(static_cast(inner)); - return true; } + value_conv inner_caster; + if (!inner_caster.load(src, convert)) + return false; + + value.emplace(inner_caster.operator typename value_conv::template cast_op_type()); + return true; } - PYBIND11_TYPE_CASTER(T, _("Optional[") + caster_type::name() + _("]")); - -private: - caster_type inner; + PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]")); }; #if PYBIND11_HAS_OPTIONAL diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index 33f8a43a..378da522 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -64,6 +64,15 @@ private: }; PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr); +/// Issue #528: templated constructor +struct TplConstrClass { + template TplConstrClass(const T &arg) : str{arg} {} + std::string str; + bool operator==(const TplConstrClass &t) const { return t.str == str; } +}; +namespace std { +template <> struct hash { size_t operator()(const TplConstrClass &t) const { return std::hash()(t.str); } }; +} void init_issues(py::module &m) { @@ -371,6 +380,16 @@ void init_issues(py::module &m) { py::class_(m2, "MyDerived") .def_static("make", &MyDerived::make) .def_static("make2", &MyDerived::make); + + /// Issue #528: templated constructor + m2.def("tpl_constr_vector", [](std::vector &) {}); + m2.def("tpl_constr_map", [](std::unordered_map &) {}); + m2.def("tpl_constr_set", [](std::unordered_set &) {}); +#if defined(PYBIND11_HAS_OPTIONAL) + m2.def("tpl_constr_optional", [](std::optional &) {}); +#elif defined(PYBIND11_HAS_EXP_OPTIONAL) + m2.def("tpl_constr_optional", [](std::experimental::optional &) {}); +#endif } // MSVC workaround: trying to use a lambda here crashes MSCV