[Python] pybind11: Binding a function with an abstract reference argument

Discussão em 'Python' iniciado por Stack, Junho 5, 2025.

  1. Stack

    Stack Membro Participativo

    I want to bind a function that takes a lambda (std::function) as an argument. The lambda itself has a reference to an abstract type as an argument. When I attempt to invoke the function in python, I get an error because the abstract type is not copyable.

    Below is a small example. I have an interface IFoo which is abstract and its concrete implementation Foo. I then have a function evaluate which takes as an argument a std::function<void(IFoo&)>.

    I would prefer not to expose the concrete implementation in the python binding so I only bind the interface.

    #include <iostream>

    #include <pybind11/pybind11.h>
    #include <pybind11/functional.h>

    namespace py = pybind11;

    class IFoo
    {
    public:
    virtual ~IFoo() = default;
    virtual void setValue(int a) = 0;
    };

    class Foo : public IFoo
    {
    public:
    ~Foo() override = default;

    void setValue(int a) override { m_a = a; }
    int getValue() const { return m_a; }
    protected:
    int m_a{18};
    };

    int evaluate(std::function<void(IFoo&)>&& callback)
    {
    Foo foo;
    callback(foo);
    return foo.getValue() + 34;
    }

    PYBIND11_MODULE(libbindtest, module)
    {
    py::class_< IFoo >(module, "Foo").def("setValue", &IFoo::setValue);
    module.def("evaluate", &evaluate);
    }

    /*
    int main (int, char**)
    {
    int res1 = evaluate([](auto& foo){ foo.setValue(22); });
    int res2 = evaluate([](auto&){});
    std::cout << "Res1: " << res1 << " Res2: " << res2 << std::endl;
    return 0;
    }
    */


    This builds fine and runs with this definition of main.

    My python looks like

    import libbindtest as bt

    def foo_operator(foo: bt.Foo):
    foo.setValue(22)

    x = bt.evaluate(foo_operator)


    With this, I get the error

    Traceback (most recent call last):
    File "/path/to/bindtest.py", line 6, in <module>
    x = bt.evaluate(foo_operator)
    RuntimeError: return_value_policy = copy, but type IFoo is non-copyable!


    I don't understand why IFoo needs to be copyable here. If I change the function definition to

    int evaluate(std::function<void(IFoo*)>&& callback)


    then everything works fine. Does someone know what I'm missing here.

    Continue reading...

Compartilhe esta Página