Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disambiguate non-const and const access methods (Pybind11)

Tags:

c++

pybind11

I am trying to wrap some C++ class using Pybind11. The class (Alpha) two getters, one returning a const reference to a member force_ the other one returning a non-const reference.

struct Dummy {
  double x{3.3};
};

class Alpha {

 const Dummy& force() const {return force_;}
 Dummy& force() {return force_;}
 
 private:
   Dummy force_;
};

I initially tried using the py::return_value_policy however this way, it seems like i didn't correctly disambiguate between the two versions of function force() as I am getting note: template argument deduction/substitution failed: and couldn’t deduce template parameter ‘Func’

py::class_<Alpha>(m, "Alpha")
      .def(py::init())
      .def("force", &Alpha::force, "returns reference", py::return_value_policy::reference_internal)
      .def("force", &Alpha::force, "returns copy", py::return_value_policy::copy);
}

Am I heading in a completely wrong direction? I do not really want do alter the C++ side of the code. A side question would be: How could I write &Alpha::force unambiguously to either mean the const or non-const version.

like image 288
Flo Ryan Avatar asked Oct 19 '25 11:10

Flo Ryan


1 Answers

I don't know pybind, but I suppose Func is the type that def tries to deduce from its second parameter. The issue is that you cannot get a function pointer to an overload set. You can only get a function pointer to a single function.

The documentation states that Func can be a plain C++ function, a function pointer, or a lambda function

Ok, but it cannot be a whole set of overloads!

Thats why with your class (I had to make force public!), this won't work for the same reason:

int main() {
    auto x = &Alpha::force;
}

Resulting error is:

<source>:15:10: error: variable 'x' with type 'auto' has incompatible initializer of type '<overloaded function type>'
    auto x = &Alpha::force;
         ^   ~~~~~~~~~~~~~

There is just no way to deduce the type from &Alpha::force alone.


You can pick one from the overload set via a static_cast:

auto x = static_cast< const Dummy& (Alpha::*)() const>(&Alpha::force);

Similar for the non-const:

auto y = static_cast< Dummy& (Alpha::*)()>(&Alpha::force);

PS: Your quote from the docs actually do not mention member functions. I suppose thats due to an incomplete quote. If def cannot accept member function pointers you would have to either make force static, or wrap the call in a free function / lambda. Don't forget that pointers to member functions are fundamentally different from pointers to free functions (they need an object to be called).

like image 69
463035818_is_not_a_number Avatar answered Oct 20 '25 23:10

463035818_is_not_a_number