Home > Net >  Cython: error: no matching function for call to …
Cython: error: no matching function for call to …

Time:08-29

I'm taking my first steps in Cython to write a Python extension of some C code. Also, I have only superficial knowledge of C . Now I face an error which I do not understand, when cythonizing my .pyx file. The C 11 code is generated successfully, but that code does not compile. The first lines of the compiler error message are:

$ python setup.py build_ext --inplace
Compiling py_foo.pyx because it changed.
[1/1] Cythonizing py_foo.pyx
running build_ext
building 'pyfoo' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c ./example.cpp -o build/temp.linux-x86_64-3.9/./example.o -std=c  11
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c ./foo.cpp -o build/temp.linux-x86_64-3.9/./foo.o -std=c  11
gcc -pthread -B /home/…/compiler_compat -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -Wall -fPIC -O2 -isystem /home/…/include -I/home/…/include -fPIC -O2 -isystem /home/…/include -fPIC -I. -I./ -I/home/…/include/python3.9 -c py_foo.cpp -o build/temp.linux-x86_64-3.9/py_foo.o -std=c  11
py_foo.cpp: In function ‘void __pyx_pf_5pyfoo_9PyDerived_2__dealloc__(__pyx_obj_5pyfoo_PyDerived*)’:
py_foo.cpp:1913:24: warning: deleting object of polymorphic class type ‘nspace::Derived’ which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]
 1913 |   delete __pyx_v_self->c_derived;
      |                        ^~~~~~~~~
py_foo.cpp: In function ‘int __pyx_pf_5pyfoo_5PyFoo___cinit__(__pyx_obj_5pyfoo_PyFoo*, __pyx_obj_5pyfoo_PyBase*)’:
py_foo.cpp:2134:66: error: no matching function for call to ‘std::unique_ptr<nspace::Base>::unique_ptr(PyObject*&)’
 2134 |     __pyx_t_2 = new nspace::Foo(((std::unique_ptr<nspace::Base> )__pyx_t_1));
      |                                                                  ^~~~~~~~~
In file included from /usr/include/c  /9/memory:80,
                 from py_foo.cpp:729:
/usr/include/c  /9/bits/unique_ptr.h:281:2: note: candidate: ‘template<class _Up, class> std::unique_ptr<_Tp, _Dp>::unique_ptr(std::auto_ptr<_Up>&&)’
  281 |  unique_ptr(auto_ptr<_Up>&& __u) noexcept;
      |  ^~~~~~~~~~
/usr/include/c  /9/bits/unique_ptr.h:281:2: note:   template argument deduction/substitution failed:
py_foo.cpp:2134:66: note:   mismatched types ‘std::auto_ptr<_Up>’ and ‘PyObject*’ {aka ‘_object*’}
 2134 |     __pyx_t_2 = new nspace::Foo(((std::unique_ptr<nspace::Base> )__pyx_t_1));
      |
...

These are the relevant files of my MWE:

example.h:

#ifndef EXAMPLE_H
#define EXAMPLE_H

namespace nspace
{
    class Base
    {
    public:
        virtual void print_() const = 0;
    };

    class Derived : public Base
    {
    private:
        int i;

    public:
        Derived(int i);
        void print_() const;
    };
}
#endif /* EXAMPLE_H */

example.cpp:

#include <iostream>
#include "example.h"


namespace nspace
{
    Derived::Derived(int i)
    {
        this->i = i;
    }

    void Derived::print_() const
    {
        std::cout << this->i << std::endl;
    }
}

foo.h:

#ifndef FOO_H
#define FOO_H

#include <memory>
#include "example.h"

namespace nspace
{
    class Foo
    {
    public:
        Foo();
        Foo(std::unique_ptr<Base> base);
        void print_();

    private:
        std::unique_ptr<Base> base;
    };
}

#endif // FOO_H

foo.cpp:

#include "foo.h"
#include "example.h"

namespace nspace
{
    Foo::Foo()
    {
        this->base = std::unique_ptr<Base>(new Derived(0));
    }

    Foo::Foo(std::unique_ptr<Base> base)
    {
        this->base = std::move(base);
    }

    void Foo::print_()
    {
        this->base->print_();
    }
}

cpp_foo.pxd:

from libcpp.memory cimport unique_ptr


cdef extern from "foo.h" namespace "nspace":
    cdef cppclass Foo:
        Foo() except  
        Foo(unique_ptr[Base] cpp_base) except  
        print_()

cdef extern from "example.h" namespace "nspace":
    cdef cppclass Base:
        pass

    cdef cppclass Derived(Base):
        Derived(int i) except  

py_foo.pyx:

# distutils: language = c  
# distutils: extra_compile_args = -std=c  11

cimport cython
from cpp_foo cimport Foo, Base, Derived
from libcpp.memory cimport unique_ptr


cdef class PyBase:
    pass

cdef class PyDerived(PyBase):
    cdef Derived* c_derived

    def __cinit__(self, int i):
        self.c_derived = new Derived(i)

    def __dealloc__(self):
        del self.c_derived


cdef class PyFoo:
    cdef Foo* foo

    def __cinit__(self, PyBase py_base):
        self.foo = new Foo(
            cpp_base=<unique_ptr[Base]>(py_base.c_derived)
        )


    def __dealloc__(self):
        del self.foo

    def print_(self):
        self.foo.print_()

setup.py:

from distutils.core import setup, Extension

from Cython.Build import cythonize

extensions = [
    Extension("pyfoo",
        sources=[
            "py_foo.pyx",
            "./foo.cpp",
            "./example.cpp",
        ],
        include_dirs=["./"]
    )
]

setup(
    ext_modules=cythonize(
        extensions,
        language_level=3,
    ),
)

I'm very sure my error comes from a misconception I have regarding Cython (and maybe C too). Any help or tip is appreciated.

CodePudding user response:

There's a few problems. I've listed three that I've spotted quickly but there may well be more.

The cast

I think you want to call unique_ptr rather than cast to it

cpp_base=unique_ptr[Base](py_base.c_derived)

The <> cast generates a C-style cast which the C compiler doesn't know what to do with.

py_base doesn't have an attribute c_derived

Therefore this'll default to assuming that c_derived is a Python attribute returning a Python object.

PyDerived has the attribute c_derived. If you want to access this attribute then the argument to PyFoo.__cinit__ needs to be of type PyDerived.

Ownership

By wrapping py_base.c_derived with a unique_ptr you're passing ownership to the unique_ptr. Despite this, py_base still believes it owns this pointer and will delete it in __dealloc__.

  • Related