diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 3486af3b..42d381bb 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -773,93 +773,51 @@ protected: }; template class type_caster> { - typedef std::tuple type; - typedef std::tuple...> itype; - typedef std::tuple args_type; - typedef std::tuple args_kwargs_type; + using type = std::tuple; + using indices = typename make_index_sequence::type; + static constexpr auto size = sizeof...(Tuple); + public: - enum { size = sizeof...(Tuple) }; - - static constexpr const bool has_kwargs = std::is_same::value; - static constexpr const bool has_args = has_kwargs || std::is_same::value; - bool load(handle src, bool convert) { if (!src || !PyTuple_Check(src.ptr()) || PyTuple_GET_SIZE(src.ptr()) != size) return false; - return load(src, convert, typename make_index_sequence::type()); - } - - template ::value && - !std::is_same::value, int> = 0> - bool load_args(handle args, handle, bool convert) { - return load(args, convert, typename make_index_sequence::type()); - } - - template ::value, int> = 0> - bool load_args(handle args, handle, bool convert) { - std::get<0>(value).load(args, convert); - return true; - } - - template ::value, int> = 0> - bool load_args(handle args, handle kwargs, bool convert) { - std::get<0>(value).load(args, convert); - std::get<1>(value).load(kwargs, convert); - return true; + return load_impl(src, convert, indices{}); } static handle cast(const type &src, return_value_policy policy, handle parent) { - return cast(src, policy, parent, typename make_index_sequence::type()); - } - - static PYBIND11_DESCR element_names() { - return detail::concat(make_caster::name()...); + return cast_impl(src, policy, parent, indices{}); } static PYBIND11_DESCR name() { - return type_descr(_("Tuple[") + element_names() + _("]")); - } - - template enable_if_t::value, ReturnValue> call(Func &&f) { - return call(std::forward(f), typename make_index_sequence::type()); - } - - template enable_if_t::value, void_type> call(Func &&f) { - call(std::forward(f), typename make_index_sequence::type()); - return void_type(); + return type_descr(_("Tuple[") + detail::concat(make_caster::name()...) + _("]")); } template using cast_op_type = type; - operator type() { - return cast(typename make_index_sequence::type()); - } + operator type() { return implicit_cast(indices{}); } protected: - template ReturnValue call(Func &&f, index_sequence) { - return f(cast_op(std::get(value))...); - } + template + type implicit_cast(index_sequence) { return type(cast_op(std::get(value))...); } - template type cast(index_sequence) { - return type(cast_op(std::get(value))...); - } + static constexpr bool load_impl(handle, bool, index_sequence<>) { return true; } - template bool load(handle src, bool convert, index_sequence) { - std::array success {{ - std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Indices), convert)... - }}; - (void) convert; /* avoid a warning when the tuple is empty */ - for (bool r : success) + template + bool load_impl(handle src, bool convert, index_sequence) { + for (bool r : {std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...}) if (!r) return false; 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(const type &src, return_value_policy policy, handle parent, index_sequence) { + template + static handle cast_impl(const type &src, return_value_policy policy, handle parent, index_sequence) { std::array entries {{ - reinterpret_steal(make_caster::cast(std::get(src), policy, parent))... + reinterpret_steal(make_caster::cast(std::get(src), policy, parent))... }}; for (const auto &entry: entries) if (!entry) @@ -1239,6 +1197,69 @@ constexpr arg operator"" _a(const char *name, size_t) { return arg(name); } } NAMESPACE_BEGIN(detail) + +/// Helper class which loads arguments for C++ functions called from Python +template +class argument_loader { + using itypes = type_list...>; + using indices = typename make_index_sequence::type; + +public: + static constexpr auto has_kwargs = std::is_same>::value; + static constexpr auto has_args = has_kwargs || std::is_same>::value; + + static PYBIND11_DESCR arg_names() { return detail::concat(make_caster::name()...); } + + bool load_args(handle args, handle kwargs, bool convert) { + return load_impl(args, kwargs, convert, itypes{}); + } + + template + enable_if_t::value, Return> call(Func &&f) { + return call_impl(std::forward(f), indices{}); + } + + template + enable_if_t::value, void_type> call(Func &&f) { + call_impl(std::forward(f), indices{}); + return void_type(); + } + +private: + bool load_impl(handle args_, handle, bool convert, type_list) { + std::get<0>(value).load(args_, convert); + return true; + } + + bool load_impl(handle args_, handle kwargs_, bool convert, type_list) { + std::get<0>(value).load(args_, convert); + std::get<1>(value).load(kwargs_, convert); + return true; + } + + bool load_impl(handle args, handle, bool convert, ... /* anything else */) { + return load_impl_sequence(args, convert, indices{}); + } + + static constexpr bool load_impl_sequence(handle, bool, index_sequence<>) { return true; } + + template + bool load_impl_sequence(handle src, bool convert, index_sequence) { + for (bool r : {std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...}) + if (!r) + return false; + return true; + } + + template + Return call_impl(Func &&f, index_sequence) { + return std::forward(f)(cast_op(std::get(value))...); + } + +private: + std::tuple...> value; +}; + NAMESPACE_BEGIN(constexpr_impl) /// Implementation details for constexpr functions constexpr int first(int i) { return i; } diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 74dcbd92..5622ad95 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -368,6 +368,9 @@ template using intrinsic_t = typename intrinsic_type::type; /// Helper type to replace 'void' in some expressions struct void_type { }; +/// Helper template which holds a list of types +template struct type_list { }; + /// from __cpp_future__ import (convenient aliases from C++14/17) template using bool_constant = std::integral_constant; template using negation = bool_constant; diff --git a/include/pybind11/functional.h b/include/pybind11/functional.h index dbeea5dc..f1b0ebbb 100644 --- a/include/pybind11/functional.h +++ b/include/pybind11/functional.h @@ -70,7 +70,7 @@ public: } PYBIND11_TYPE_CASTER(type, _("Callable[[") + - type_caster>::element_names() + _("], ") + + argument_loader::arg_names() + _("], ") + type_caster::name() + _("]")); }; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index c88273d5..b737dc7f 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -111,10 +111,10 @@ protected: } /* Type casters for the function arguments and return value */ - typedef detail::type_caster> cast_in; - typedef detail::type_caster::value, detail::void_type, - typename detail::intrinsic_type::type>::type> cast_out; + using cast_in = detail::argument_loader; + using cast_out = detail::make_caster< + detail::conditional_t::value, detail::void_type, Return> + >; /* Dispatch code which converts function arguments and performs the actual function call */ rec->impl = [](detail::function_record *rec, handle args, handle kwargs, handle parent) -> handle { @@ -151,7 +151,7 @@ protected: /* Generate a readable signature describing the function's arguments and return value types */ using detail::descr; using detail::_; - PYBIND11_DESCR signature = _("(") + cast_in::element_names() + _(") -> ") + cast_out::name(); + PYBIND11_DESCR signature = _("(") + cast_in::arg_names() + _(") -> ") + cast_out::name(); /* Register the function with Python from generic (non-templated) code */ initialize_generic(rec, signature.text(), signature.types(), sizeof...(Args));