I have a function :
void my_functions(int a, int b = 42);
And I want to bind it using only the default argument for b
:
m.def("my_functions", &my_functions, pb::arg("b") = 42); // just default for b
This doesn't work, I get:
/cache/venv/include/pybind11/pybind11.h:219:40: error: static assertion failed: The number of argument annotations does not match the number of function arguments
219 | expected_num_args<Extra...>(
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^
220 | sizeof...(Args), cast_in::args_pos >= 0, cast_in::has_kwargs),
What's the right way of doing it?
Answer
The issue you are encountering arises because pybind11
expects the number of arguments to match the function's signature when you define the function binding. In your case, you want to specify the default argument only for b
, but the function signature still requires a
to be passed in when calling the function.
The correct way to bind a function with default arguments in pybind11
is to use py::arg
for the arguments that you want to explicitly specify, and for the default arguments, simply don't add them in the py::arg
list. pybind11
will automatically apply the default values based on the C++ function signature.
Here’s how you can correctly bind your function my_functions
with the default value for b
:
C++ function:
void my_functions(int a, int b = 42);
Pybind11 binding:
m.def("my_functions", &my_functions, py::arg("a"), py::arg("b") = 42);
Explanation:
py::arg("a")
explicitly binds the first argumenta
.py::arg("b") = 42
binds the second argumentb
and provides its default value of42
. This means ifb
is not passed when calling the Python function, it will automatically use42
as the default value.
You don't need to specify the default for b
manually in the m.def
call — pybind11
will handle it correctly by looking at the default argument in the C++ function signature.
Final Example:
#include <pybind11/pybind11.h>
namespace py = pybind11;
void my_functions(int a, int b = 42) {
// Your function implementation
std::cout << "a: " << a << ", b: " << b << std::endl;
}
PYBIND11_MODULE(example, m) {
m.def("my_functions", &my_functions, py::arg("a"), py::arg("b") = 42);
}
In Python, you can now call the function with either one or two arguments:
import example
example.my_functions(10) # Uses the default for `b`, prints: "a: 10, b: 42"
example.my_functions(10, 20) # Uses 20 for `b`, prints: "a: 10, b: 20"
This approach should solve the error and work correctly.