I have found a specific case in which the overload_cast
fails, and I have no idea how to solve this.
A minimal example that shows the behavior is
#include <pybind11/pybind11.h>
// ----------------
template<class InputIterator, class OutputIterator>
void absolute(
const InputIterator first, const InputIterator last, const OutputIterator result
)
{
for ( auto it = first ; it != last ; ++it )
*it = std::abs(*it);
}
// ----------------
std::vector<double> absolute(const std::vector<double> &in)
{
std::vector<double> out = in;
for ( auto &i: out )
i = std::abs(i);
return out;
}
// ----------------
namespace py = pybind11;
PYBIND11_MODULE(example,m)
{
m.def("absolute", py::overload_cast<const std::vector<double>&>(&absolute));
}
Compiling using e.g.:
clang++ -O3 -shared -std=c++14 `python3-config --cflags --ldflags --libs` example.cpp -o example.so -fPIC
Gives:
example.cpp:32:21: error: no matching function for call to object of type 'const
detail::overload_cast_impl<const vector<double, allocator<double> > &>'
m.def("absolute", py::overload_cast<const std::vector<double>&>(&absolute));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/pybind11/detail/common.h:727:20: note: candidate template ignored: couldn't infer
template argument 'Return'
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
^
/usr/local/include/pybind11/detail/common.h:731:20: note: candidate template ignored: couldn't infer
template argument 'Return'
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
^
/usr/local/include/pybind11/detail/common.h:735:20: note: candidate function template not viable:
requires 2 arguments, but 1 was provided
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
^
1 error generated.
Removing the first function (that I do not which to overload), or changing its signature solves the problem. But that is obviously not what I want.
using sig = std::vector<double>(const std::vector<double> &in);
py::overload_cast<const std::vector<double>&>((sig*)&absolute)
Unlike almost anything else in C++, &absolute
doesn't refer to an actual value or object.
Instead it refers to an overload set; in this case, an overload set that includes both a specific signature and a template.
Template pattern matching which is used to deduce Return
fails.
By casting to a specific signature, (sig*)&absolute
now refers to an object or value -- in this case, a pointer to a specific function. Now template pattern matching can deduce the type of Return
.
In C++, the general rule is that callables don't have specific signatures. You can ask what a callable invoked with specific arguments returns, but it is bad form to ask a callable what arguments it wants to be invoked with. It is also bad form to assume a callable is a PMF or a function pointer.
People hack around this all the time, and it leads to annoying errors like your code demonstrates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With