Skip to content

Commit 1e5bc66

Browse files
authored
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
1 parent cc36ac5 commit 1e5bc66

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

include/pybind11/pybind11.h

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,49 @@ inline std::string generate_type_signature() {
248248
# define PYBIND11_COMPAT_STRDUP strdup
249249
#endif
250250

251+
#define PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR \
252+
detail::const_name("(") + cast_in::arg_names + detail::const_name(") -> ") + cast_out::name
253+
254+
// We factor out readable function signatures to a specific template
255+
// so that they don't get duplicated across different instantiations of
256+
// cpp_function::initialize (which is templated on more types).
257+
template <typename cast_in, typename cast_out>
258+
class ReadableFunctionSignature {
259+
public:
260+
using sig_type = decltype(PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR);
261+
262+
private:
263+
// We have to repeat PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR in decltype()
264+
// because C++11 doesn't allow functions to return `auto`. (We don't
265+
// know the type because it's some variant of detail::descr<N> with
266+
// unknown N.)
267+
static constexpr sig_type sig() { return PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR; }
268+
269+
public:
270+
static constexpr sig_type kSig = sig();
271+
// We can only stash the result of detail::descr::types() in a
272+
// constexpr variable if we aren't on MSVC (see
273+
// PYBIND11_DESCR_CONSTEXPR).
274+
#if !defined(_MSC_VER)
275+
using types_type = decltype(sig_type::types());
276+
static constexpr types_type kTypes = sig_type::types();
277+
#endif
278+
};
279+
#undef PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR
280+
281+
// Prior to C++17, we don't have inline variables, so we have to
282+
// provide an out-of-line definition of the class member.
283+
#if !defined(PYBIND11_CPP17)
284+
template <typename cast_in, typename cast_out>
285+
constexpr typename ReadableFunctionSignature<cast_in, cast_out>::sig_type
286+
ReadableFunctionSignature<cast_in, cast_out>::kSig;
287+
# if !defined(_MSC_VER)
288+
template <typename cast_in, typename cast_out>
289+
constexpr typename ReadableFunctionSignature<cast_in, cast_out>::types_type
290+
ReadableFunctionSignature<cast_in, cast_out>::kTypes;
291+
# endif
292+
#endif
293+
251294
PYBIND11_NAMESPACE_END(detail)
252295

253296
/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object
@@ -481,9 +524,14 @@ class cpp_function : public function {
481524

482525
/* Generate a readable signature describing the function's arguments and return
483526
value types */
484-
static constexpr auto signature
485-
= const_name("(") + cast_in::arg_names + const_name(") -> ") + cast_out::name;
486-
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
527+
static constexpr const auto &signature
528+
= detail::ReadableFunctionSignature<cast_in, cast_out>::kSig;
529+
#if !defined(_MSC_VER)
530+
static constexpr const auto &types
531+
= detail::ReadableFunctionSignature<cast_in, cast_out>::kTypes;
532+
#else
533+
PYBIND11_DESCR_CONSTEXPR auto types = std::decay<decltype(signature)>::type::types();
534+
#endif
487535

488536
/* Register the function with Python from generic (non-templated) code */
489537
// Pass on the ownership over the `unique_rec` to `initialize_generic`. `rec` stays valid.

0 commit comments

Comments
 (0)