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

私はgcc-4.7を使用してブースト1.48、Python-2.7をFedora17でコンパイルしています。すべてのコードは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

コンパイラは大量のブースト内部エラーを返しますが、ここに投稿するには多すぎます。この抜粋がその核心のようです。その前に「必須」と後の「メモ」がたくさんあります。

/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::pythonPythonはサポートしていないため、Pythonで不変になる型への参照を返すことを防ぎます。 x値を保存しません5; 代わりに、5オブジェクトへの参照が含まれています。に割り当ててxも再バインドされなかった場合はx、などの無意味なステートメント6 = 5が可能になります。

コンパイルエラーは静的チェックでありreturn_internal_reference、クラスまたはユニオンでのみ機能するように制限されています。これらはPython内で変更可能なタイプであるためです。動作する「より複雑なクラステンプレート」は、ユーザータイプへの参照を返すことだと思います。

于 2012-06-21T18:45:10.037 に答える
0

簡単な答えは、おそらくフロートへの内部参照を返したくないということです。Pythonでは、数値は不変であるため、コピーを返すだけの方が安全であり、機能や速度を犠牲にすることはありません。

より複雑なもの(リストや別のラップされたクラスへの参照など)を返したい場合はできますが、それでもほとんどの場合、必要なものではありません。一方のオブジェクトがもう一方のオブジェクトに依存していると、脆弱性が生じます。オブジェクトの内部状態を変更できるようにしたい場合は、ゲッターとセッターを使用し、データをコピーして出し入れする方がよいでしょう。

于 2012-06-21T18:19:54.673 に答える