diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 22eceb05f..e814cab94 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1255,50 +1255,13 @@ public: template using cast_op_type = remove_reference_t>; }; -template class type_caster> { - typedef std::pair type; -public: - bool load(handle src, bool convert) { - if (!isinstance(src)) - return false; - const auto seq = reinterpret_borrow(src); - if (seq.size() != 2) - return false; - return first.load(seq[0], convert) && second.load(seq[1], convert); - } - - static handle cast(const type &src, return_value_policy policy, handle parent) { - auto o1 = reinterpret_steal(make_caster::cast(src.first, policy, parent)); - auto o2 = reinterpret_steal(make_caster::cast(src.second, policy, parent)); - if (!o1 || !o2) - return handle(); - tuple result(2); - PyTuple_SET_ITEM(result.ptr(), 0, o1.release().ptr()); - PyTuple_SET_ITEM(result.ptr(), 1, o2.release().ptr()); - return result.release(); - } - - static PYBIND11_DESCR name() { - return type_descr( - _("Tuple[") + make_caster::name() + _(", ") + make_caster::name() + _("]") - ); - } - - template using cast_op_type = type; - - operator type() & { return type(cast_op(first), cast_op(second)); } - operator type() && { return type(cast_op(std::move(first)), cast_op(std::move(second))); } -protected: - make_caster first; - make_caster second; -}; - -template class type_caster> { - using type = std::tuple; - using indices = make_index_sequence; +// Base implementation for std::tuple and std::pair +template class TupleType, typename... Tuple> class tuple_caster { + using type = TupleType; static constexpr auto size = sizeof...(Tuple); - + using indices = make_index_sequence; public: + bool load(handle src, bool convert) { if (!isinstance(src)) return false; @@ -1327,7 +1290,6 @@ protected: template type implicit_cast(index_sequence) && { return type(cast_op(std::move(std::get(subcasters)))...); } - static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; } template @@ -1338,9 +1300,6 @@ protected: return true; } - static handle cast_impl(const type &, return_value_policy, handle, - index_sequence<>) { return tuple().release(); } - /* Implementation: Convert a C++ tuple into a Python tuple */ template static handle cast_impl(const type &src, return_value_policy policy, handle parent, index_sequence) { @@ -1357,9 +1316,15 @@ protected: return result.release(); } - std::tuple...> subcasters; + TupleType...> subcasters; }; +template class type_caster> + : public tuple_caster {}; + +template class type_caster> + : public tuple_caster {}; + /// Helper class which abstracts away certain actions. Users can provide specializations for /// custom holders, but it's only necessary if the type has a non-standard interface. template diff --git a/tests/test_builtin_casters.cpp b/tests/test_builtin_casters.cpp index 55269bac6..673340230 100644 --- a/tests/test_builtin_casters.cpp +++ b/tests/test_builtin_casters.cpp @@ -85,7 +85,7 @@ TEST_SUBMODULE(builtin_casters, m) { m.def("tuple_passthrough", [](std::tuple input) { return std::make_tuple(std::get<2>(input), std::get<1>(input), std::get<0>(input)); }, "Return a triple in reversed order"); - + m.def("empty_tuple", []() { return std::tuple<>(); }); // test_builtins_cast_return_none m.def("return_none_string", []() -> std::string * { return nullptr; }); diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index a6f9b57af..32eba45f3 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -188,6 +188,7 @@ def test_tuple(doc): # Any sequence can be cast to a std::pair or std::tuple assert m.pair_passthrough([True, "test"]) == ("test", True) assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) + assert m.empty_tuple() == () assert doc(m.pair_passthrough) == """ pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool]