简体   繁体   中英

How to pass float to a pybind11 function expecting an int

I copied the example from the pybind11 documentation:

#include <pybind11/pybind11.h>
namespace py = pybind11;
int add(int i, int j) {
    return i + j;
}
PYBIND11_MODULE(example, m) {
    m.def("add", &add, "A function which adds two numbers");
}

Built it like so:

g++ -fPIC -shared -I/usr/include/python3.7 -o example.so example.cpp

Then:

$ python3
Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from example import *
>>> add(1, 2)
3
>>> add(1.0, 2.0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: add(): incompatible function arguments. The following argument types are supported:
    1. (arg0: int, arg1: int) -> int

Invoked with: 1.0, 2.0
>>>

I realize I could rewrite add to take double arguments and then truncate them inside the body of add . But is there a way to tell pybind11 that it's ok to to pass floats to the function (even though it takes int arguments) and have it perform the conversion automatically?

According to the docs, the opposite (conversion from integer types to double ) is done implicitly and automatically.

Silently and implicitly truncating to int is a terrible thing to allow, and pybind11 won't do it for you. If you must allow it, you can make an overloaded function for each parameter type, and have the double variant do the truncation on your behalf (keep in mind, this might not just lose precision after the decimal; double can express numbers much larger than any integer type, so bad things'll happen for such numbers).

A rough example for doing this would be:

#include <pybind11/pybind11.h>
namespace py = pybind11;
int add_int(int i, int j) {
    return i + j;
}
int add_double_as_int(double i, double j) {
    return add_int((int)i, (int)j);
}

PYBIND11_MODULE(example, m) {
    m.def("add", &add_int, "A function which adds two integers");
    m.def("add", &add_double_as_int, "A function which adds two floats after truncating to int");
}

At the C++ level, the functions have different names (you might be able to avoid this with creative casting similar to the examples for doing it with class methods , but it's hardly worth the trouble), but at the Python level, they'll appear as a single API with multiple prototypes described in the documentation.

C++ is strongly typed. It will do automatic type conversion of basic types only when it can be done safely. Since an integer can't represent every value that a double can C++ can't automatically perform the conversion. So you'll need to explicitly do the conversion yourself. I'm not sure how this is done in python. In C++ it is best done with:

#include \<cmath\>

double dbl = 3.5;

int newval = std::round(dbl);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM