Factor out readable function signatures to avoid duplication (#5857)

* Centralize readable function signatures to avoid duplication

This seems to reduce size costs of adding enum_-specific implementations of dunder methods, but also should provide a nice to have size optimization for programs that use pybind11 in general.

* gate disabling of -Wdeprecated-redundant-constexpr-static-def to clang 17+

* fix gating to include Apple Clang 15

* Make GCC happy with types

* fix apple clang gating again. suppress -Wdeprecated for GCC

* Gate warning suppressions to C++17. Suppress -Wdeprecated for clang as well.

* hopefully fix last straggler CI job

* attempt to address readability review feedback from @rwgk

* drop warning suppressions and instead just gate compilation the pre-C++17 compat code
This commit is contained in:
Scott Wolchok
2025-10-15 21:12:44 -07:00
committed by GitHub
parent cc36ac51a0
commit 1e5bc66e38

View File

@@ -248,6 +248,49 @@ inline std::string generate_type_signature() {
# define PYBIND11_COMPAT_STRDUP strdup
#endif
#define PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR \
detail::const_name("(") + cast_in::arg_names + detail::const_name(") -> ") + cast_out::name
// We factor out readable function signatures to a specific template
// so that they don't get duplicated across different instantiations of
// cpp_function::initialize (which is templated on more types).
template <typename cast_in, typename cast_out>
class ReadableFunctionSignature {
public:
using sig_type = decltype(PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR);
private:
// We have to repeat PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR in decltype()
// because C++11 doesn't allow functions to return `auto`. (We don't
// know the type because it's some variant of detail::descr<N> with
// unknown N.)
static constexpr sig_type sig() { return PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR; }
public:
static constexpr sig_type kSig = sig();
// We can only stash the result of detail::descr::types() in a
// constexpr variable if we aren't on MSVC (see
// PYBIND11_DESCR_CONSTEXPR).
#if !defined(_MSC_VER)
using types_type = decltype(sig_type::types());
static constexpr types_type kTypes = sig_type::types();
#endif
};
#undef PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR
// Prior to C++17, we don't have inline variables, so we have to
// provide an out-of-line definition of the class member.
#if !defined(PYBIND11_CPP17)
template <typename cast_in, typename cast_out>
constexpr typename ReadableFunctionSignature<cast_in, cast_out>::sig_type
ReadableFunctionSignature<cast_in, cast_out>::kSig;
# if !defined(_MSC_VER)
template <typename cast_in, typename cast_out>
constexpr typename ReadableFunctionSignature<cast_in, cast_out>::types_type
ReadableFunctionSignature<cast_in, cast_out>::kTypes;
# endif
#endif
PYBIND11_NAMESPACE_END(detail)
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
@@ -481,9 +524,14 @@ protected:
/* Generate a readable signature describing the function's arguments and return
value types */
static constexpr auto signature
= const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name;
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
static constexpr const auto &signature
= detail::ReadableFunctionSignature<cast_in, cast_out>::kSig;
#if !defined(_MSC_VER)
static constexpr const auto &types
= detail::ReadableFunctionSignature<cast_in, cast_out>::kTypes;
#else
PYBIND11_DESCR_CONSTEXPR auto types = std::decay<decltype(signature)>::type::types();
#endif
/* Register the function with Python from generic (non-templated) code */
// Pass on the ownership over the `unique_rec` to `initialize_generic`. `rec` stays valid.