如何从cython中暴露静态constexpr

时间:2017-10-26 19:48:17

标签: python c++ static cython constexpr

我需要将以下演示示例从cpp包装到cython以便在Python中使用

class Foo1 : public MFoo<unsigned int> { 
public:
    constexpr Foo1(unsigned int val) : MFoo{val} {}
    }
};

class Foo{
public:
    static constexpr Foo1 any {0};
    static constexpr Foo1 one {1<<1};
    static constexpr Foo1 two {1<<2};
};

这就是我现在拥有的 file.pxd

cdef extern from "../MFoo.hpp":
    cdef cppclass MFoo:
        pass

cdef extern from "../header.hpp":
    cdef cppclass Foo1(MFoo):
        pass

cdef extern from "../header.hpp":
    cdef cppclass Foo:
        ###@staticmethod
        Foo1 _any "Foo::any"
        Foo1 _one "Foo::one"
        Foo1 _two "Foo::two"
###any=_any
### I also need to link my cpp definitions of any,one and two 
###to cython file but I am facing Error:Python object cannot be declared extern

我的file.pyx

def Bar(self,PyFoo1 abc)
    return file.Bar(######) # how would I call something like Foo::one       

我需要知道如何在cython中包装它。我正在使用How to expose a constexpr to Cython? 这是相似的,但仍然不是很有用

1 个答案:

答案 0 :(得分:1)

你的主要问题是Cython没有提供表达C ++静态成员变量的方法。要解决此问题,您可以将它们放在全局范围内并使用字符串来确保生成正确的C ++代码。 constexpr无关紧要--Cython不需要了解它。

我已经创建了一个简单的示例,该示例与您的略有简化(例如,它省略了您不提供定义的无关模板类):

class C {
public:
    constexpr C(unsigned int) {}
};

class D {
public:
    static constexpr C any {0};
    static constexpr C one {1<<1};
    static constexpr C two {1<<2};
};

inline void bar(const C&) {}

并在cython中:

cdef extern from "whatever.hpp":
    cdef cppclass C:
        pass
    cdef cppclass D:
        pass
    C any "D::any"
    C one "D::one"
    C two "D::two"

    void bar(const C&)

请注意,我并未将anyonetwo置于D内,但请确保字符串创建C ++代码D::any

我认为还有关于如何从Python调用bar的第二个问题。显然有很多选项,但一个简单的方法是传递一个字符串,并有一个Cython函数将字符串与C ++值匹配:

# except NULL allows Cython to signal an error to the calling function
cdef const C* get_C_instance(s) except NULL:
    if s=="any":
        return &any
    elif s=="one":
        return &one
    elif s=="two":
        return &two
    raise ValueError("Unrecognised string {0}".format(s))

def py_bar(s):
    return bar(get_C_instance(s)[0])

这不是创建Python接口的唯一解决方案 - 您可以创建一个包含C的包装类,并将其实例称为anyone,例如two