ddavis
ddavis

Reputation: 357

Boost mp11 mp_for_each with additional function argument

I'm trying to pass a list of pairs of types constructed from boost::mp11::mp_product to a function that takes the pairs along with an additional function argument via boost::mp11::mp_for_each.

The docs I've found for mp_for_each are limited to use with generic lambdas or pure functions, so I can't seem to figure out if the use of std::bind is the way to go; and if it is, what I'm doing wrong yielding the following compiler error:

error: no matching function for call to 'bind'
                           std::bind(inject_foo, m, std::placeholders::_1));
                           ^~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:2953:1: note: candidate template ignored: couldn't infer template argument '_Fp'
bind(_Fp&& __f, _BoundArgs&&... __bound_args)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:2962:1: note: candidate template ignored: couldn't infer template argument '_Rp'
bind(_Fp&& __f, _BoundArgs&&... __bound_args)

Code I'm using:

#include <pybind11/numpy.h>
#include <boost/mp11.hpp>
#include <functional>

using boost::mp11::mp_product;
using boost::mp11::mp_for_each;

template <typename...> struct type_list {};

// all possible types
using my_type_list = type_list<
  double, float, py::ssize_t, int, unsigned int, unsigned long>;

// construct all possible pairs of types with help from boost::mp11
using my_type_pairs = mp_product<
  type_list, my_type_list, my_type_list>;

// the C++ function that we bind to a python module in the next function.
template <typename Tx, typename Ty>
py::array<py::ssize_t> foo(p::array_t<Tx> x, py::array_t<Ty>) {
  py::array_t<py::ssize_t> z;
  // do something with x and y
  return z;
}

// bind foo<Tx, Ty> function to py::module m
template <typename Tx, typename Ty>
void inject_foo(py::module_& m, const type_list<Tx, Ty>&) {
  m.def("_foo", &foo<Tx, Ty>, py::arg("x").noconvert(), py::arg("y").noconvert());
}

PYBIND11_MODULE(_backend, m) {
  // these function calls work as expected:
  // inject_foo(m, type_list<double, double>{});
  // inject_foo(m, type_list<double, float>{});
  // inject_foo(m, type_list<double, int>{});
  // .....

  // trying to make my life easier with the loop 
  // over all possible types of pairs is not working
  mp_for_each(pg_type_pairs{}, std::bind(inject_foo, m, std::placeholders::_1));

}

Upvotes: 1

Views: 695

Answers (1)

ddavis
ddavis

Reputation: 357

PiotrNycz's comment led to an answer:

mp_for_each<pg_type_pairs>([&](const auto& x) { inject_foo(m, x); });

Provides the desired behavior (In the question I was even using the mp_for_each API incorrectly; switching to a lambda helped find that error).

Upvotes: 1

Related Questions