From 9e62558d521efd899f986d2cf4d062adadb7d8b0 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sat, 4 Jun 2016 00:27:32 +0200 Subject: [PATCH] Check the number of named arguments at compile time --- include/pybind11/attr.h | 13 +++++++++++++ include/pybind11/pybind11.h | 9 +++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index d2525e5fc..10d848ae9 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -321,5 +321,18 @@ template struct process_attributes { } }; +/// Compile-time integer sum +constexpr size_t constexpr_sum() { return 0; } +template +constexpr size_t constexpr_sum(T n, Ts... ns) { return n + constexpr_sum(ns...); } + +/// Check the number of named arguments at compile time +template ::value...), + size_t self = constexpr_sum(std::is_same::value...)> +constexpr bool expected_num_args(size_t nargs) { + return named == 0 || (self + named) == nargs; +} + NAMESPACE_END(detail) NAMESPACE_END(pybind11) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index cfbb0f9a3..1438e3494 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -72,6 +72,9 @@ protected: /// Special internal constructor for functors, lambda functions, etc. template void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) { + static_assert(detail::expected_num_args(sizeof...(Args)), + "The number of named arguments does not match the function signature"); + struct capture { typename std::remove_reference::type f; }; /* Store the function including any extra state it might have (e.g. a lambda capture object) */ @@ -206,12 +209,6 @@ protected: } #endif - if (!rec->args.empty() && (int) rec->args.size() != args) - pybind11_fail( - "cpp_function(): function \"" + std::string(rec->name) + "\" takes " + - std::to_string(args) + " arguments, but " + std::to_string(rec->args.size()) + - " pybind11::arg entries were specified!"); - rec->signature = strdup(signature.c_str()); rec->args.shrink_to_fit(); rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");