Pybind11: Specifying type for templated functions in Python

Created on 15 Jan 2019  Â·  9Comments  Â·  Source: pybind/pybind11

Binding templated functions is nicely described in issue #199 - it's simply a matter of defining explicitly instantiated versions of the function:

template <typename T>
T square(T x) {
    return x * x;
}

PYBIND11_MODULE(module, m) {
    m.def("square", &square<double>);
    m.def("square", &square<float>);
    m.def("square", &square<int>);
}

When calling these functions in Python code, the version of the function called can be deduced from the argument type.

How can we explicitly specify which version of the function is called from Python when the function has no arguments to facilitate type deduction? E.g.:

template <typename T>
T get_something() {
    ...
    return static_cast<T>(some_value);
}

PYBIND11_MODULE(module, m) {
    m.def("get_something", &get_something<double>);
    m.def("get_something", &get_something<float>);
    m.def("get_something", &get_something<int>);
}

All 9 comments

A possible workaround would be:

template <typename T>
T get_something() {
    ...
    return static_cast<T>(some_value);
}

PYBIND11_MODULE(module, m) {
    m.def("get_something_double", &get_something<double>);
    m.def("get_something_float", &get_something<float>);
    m.def("get_something_int", &get_something<int>);
}

Then from python call get_something_foo instead of get_something.

Referencing https://github.com/pybind/pybind11/issues/1667#issuecomment-454348004 by @bstaletic

This is I expect the only route really as it is pretty much the same with SWIG

All instances of a templated function must be declared or they will not be in the library

A possible workaround would be:

template <typename T>
T get_something() {
    ...
    return static_cast<T>(some_value);
}

PYBIND11_MODULE(module, m) {
    m.def("get_something_double", &get_something<double>);
    m.def("get_something_float", &get_something<float>);
    m.def("get_something_int", &get_something<int>);
}

Then from python call get_something_foo instead of get_something.

Then how about there are multiple parameters in the template function get_something?
Like
m.def("get_something_double", &get_something<double, double, double, double>); ?

Then from python call get_something_foo instead of get_something.

Then how about there are multiple parameters in the template function get_something?
Like
m.def("get_something_double", &get_something); ?

having the same dilema … assuming the right way to do it would be to fix Something like :
m.def("get_something_double_double_double_double", &get_something<double, double, double, double>);
even if it makes my eyes bleeding...

having the same dilema …
The workaround works for me.

Hi there, round a workaround using py::overload_cast that allows overload...
details at https://pybind11.readthedocs.io/en/stable/classes.html

Hi there, round a workaround using py::overload_cast that allows overload...
details at https://pybind11.readthedocs.io/en/stable/classes.html

Does it work when T is the return type? e.g.,

template<typename T>
T getVal(){
  // something. 
   return something;
}

I'm trying to do that exact thing (return the type of the template). So far not working.

If you add all the instantiations as overloads of the same function, pybind11 will do normal overload resolution, as described here: https://pybind11.readthedocs.io/en/stable/classes.html#overloaded-methods

@bstaletic's suggestion merely makes all template function instantiations have separate function names such that there are no more overloads. You don't nééd to specify all types.

If you want to go fancy, you could probably define some kind of object that implements __getitem__, expecting a type (or multiple types), find the right function instantiation, and returns a cpp_function (i.e., if (type == py::int_) return py::cpp_function("square", &square<int>);, etc).
That would allow you to do square[int](2).

The problem is that Python doesn't really have the concept over templates and instantiations, so you'll have to come up with something yourself.

Was this page helpful?
0 / 5 - 0 ratings