间歇性错误,使用boost.python返回内部引用

时间:2012-06-21 17:35:19

标签: c++ boost c++11 boost-python

我有以下课程:

#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<>());
}

我正在使用gcc-4.7在Fedora 17上编译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内部错误,这里发布的错误太多了。这段摘录似乎是它的核心。在它之前有一堆“必需的”和之后的“注意”。

/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&lt;&gt;()参数,它就可以了。这很奇怪,因为我正在用另一个更复杂的类模板做同样的事情,它在那里工作得很好。我一直在谷歌上搜索,并且现在已经打了几乎整整一天。有人知道到底发生了什么事吗?

更新

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

2 个答案:

答案 0 :(得分: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中的可变类型。我认为“更复杂的类模板”可以返回对用户类型的引用。

答案 1 :(得分:0)

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

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