2

我有以下课程:

#include <array>

template<unsigned short D>
class Point {
private:
    std::array<float, D> coordinates;
public:
    Point() { for(int i=D-1; i>=0; --i) coordinates[i] = 0.0; }
    Point(const Point& rhs) = default;
    Point& operator=(const Point& rhs) = default;
    ~Point() = default;

    float& get_ref(const unsigned short dimension)
        { return coordinates[dimension-1]; }
};

我试图用以下方式包装它:

#include <boost/python.hpp>

BOOST_PYTHON_MODULE(fernpy) {
    using namespace boost::python;

    class_< Point<2> >("point")
        .def("__call__", &Point<2>::get_ref, return_internal_reference<>());
}

我在 Fedora 17 上使用 gcc-4.7 编译 boost 1.48、python-2.7。所有代码都是一个名为 testpy.cpp 的文件。我正在使用这些命令进行编译:

g++ -std=c++11 -g -fPIC -I/usr/include/python2.7 -c testpy.cpp
g++ -shared -g -lpython2.7 -lboost_python -o libfern.so testpy.o

编译器返回一堆 boost 内部错误,太多了,无法在此处发布。这段摘录似乎是它的核心。在它之前有一堆“required from”,在它之后有“note”。

/usr/include/boost/python/object/make_instance.hpp:27:9: error: no matching function for call to ‘assertion_failed(mpl_::failed************ boost::mpl::or_<boost::is_class<float>, boost::is_union<float>, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >::************)’

如果我从 get_ref 返回一个普通的浮点数并从包装器的 .def 行中删除 return_internal_reference<>() 参数,它工作得很好。这很奇怪,因为我正在用另一个更复杂的类模板做同样的事情,而且它在那里也能正常工作。我已经在谷歌上搜索了将近一整天的时间。有人知道到底发生了什么吗?

更新:

我最终使用了 python 中的“getitem”和“setitem”特殊方法,比如这个链接。该链接显示了如何使用访问函数的静态包装器定义漂亮的结构模板,因此您不必弄乱原始 C++ 类的接口。

4

2 回答 2

1

从 python 的角度来看,floats是不可变类型。因此,python 不允许更改值。

例如,在python中会发生以下情况:

coordinates = [ 5, 10, 15 ]
x = cooardinates[ 2 ] # Bind x to refer to the int(15) object.
x = 5                 # Rebind x to refer to the int(5) object. 
                      # Does not modify coordinates.

现在,考虑以下几点:

from fernpy import point
p = point()
x = p(2) # Bind x to refer to the float(p(2)) object.
x = 5    # Rebind x to refer to the int(5) object.
         # Does not set p.coordinates[2] to 5.

因此,boost::python防止返回对在 python 中不可变的类型的引用,因为 Python 不支持它。 x不存储值5;相反,它包含对该5对象的引用。如果分配给x没有重新绑定x,那么无意义的陈述,例如6 = 5是可能的。

编译错误是一个静态检查,仅限return_internal_reference于使用类或联合,因为它们将是 Python 中的可变类型。我想工作的“更复杂的类模板”正在返回对用户类型的引用。

于 2012-06-21T18:45:10.037 回答
0

简短的回答可能是您不想返回对浮点数的内部引用。在 Python 中,数字是不可变的,因此只返回一个副本更安全,并且不会牺牲任何特性或速度。

如果你想返回更复杂的东西(比如列表或对另一个包装类的引用),你可以,但它仍然几乎总是不是你想要的;一个对象对另一个对象的依赖引入了脆弱性。如果您希望能够修改对象的内部状态,您最好使用 getter 和 setter,并将数据复制进出。

于 2012-06-21T18:19:54.673 回答