Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`overload_cast` fails in a specific case

Tags:

c++

pybind11

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.

like image 411
Tom de Geus Avatar asked Oct 17 '25 04:10

Tom de Geus


1 Answers

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.

like image 88
Yakk - Adam Nevraumont Avatar answered Oct 18 '25 17:10

Yakk - Adam Nevraumont