1

boost.python を使用して既存のライブラリの python バインディングを作成するときに問題が発生しました。シナリオは次のとおりです。

#include<boost/python.hpp>

namespace bp = boost::python;

struct Base {
    std::stringstream _myString;
    Base() { };
    Base(const Base& base) { _myString<<base._myString.str(); }

    void getString(std::stringstream& some_string) {
        _myString.str("");
        _myString<<some_string.str();
        std::cout<<"Got string: \""<<_myString.str()<<"\""<<std::endl;
    }
};

struct BaseWrapper : Base,
                     bp::wrapper<Base>
{
    BaseWrapper() :
        Base(),
        bp::wrapper<Base>() { };

    BaseWrapper(const Base& base) :
        Base(base),
        bp::wrapper<Base>() { };

    void getString(bp::object pyObj) {
        std::string strLine = bp::extract<std::string>(pyObj);
        std::stringstream sstrLine;
        sstrLine<<strLine;
        Base::getString(sstrLine);
    }
};

struct Derived : Base
{
    Derived() : Base() { };
    Derived(const Derived& derived) : Base() { _myString<<derived._myString.str(); };
};

struct DerivedWrapper : Derived,
                        bp::wrapper<Derived>
{
    DerivedWrapper() :
        Derived(),
        bp::wrapper<Derived>() { };

    DerivedWrapper(const Derived derived) :
        Derived(derived),
        bp::wrapper<Derived>() { };
};

BOOST_PYTHON_MODULE(testInheritance){
    bp::class_<BaseWrapper>("Base")
        .def("getString", &BaseWrapper::getString);

    bp::class_<DerivedWrapper, bp::bases<Base> >("Derived");
}

(長いコード ブロックで申し訳ありません。これは、私が考えることができる最小限の例でした。)

getString()Python 文字列で動作するように BaseWrapper のメソッドをオーバーライドする必要があり、この部分が正常に動作することがわかります。

>>> import testInheritance
>>> base = testInheritance.Base()
>>> base.getString("bla")
Got string: "bla"
>>>

getStringのインスタンスから呼び出そうとするとすぐに問題が発生しDerivedます。

>>> derived = testInheritance.Derived()
>>> derived.getString("bla")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Base.getString(Derived, str)
did not match C++ signature:
    getString(BaseWrapper {lvalue}, boost::python::api::object)
>>>

ここで何が問題なのかは理解できますが、それを修正する方法がわかりません。助けていただければ幸いです!

よろしく、 eDude

4

2 に答える 2

2

問題は、 とDerivedWrapper関係がないことBaseWrapperです。したがって、DerivedWrapper は、独自の python 適応実装を提供する必要がありvoid getString(bp::object pyObj)ます。

したがって、それを機能させる1つの方法は次のとおりです。

struct DerivedWrapper : Derived,
                        bp::wrapper<Derived>
{
    DerivedWrapper() :
        Derived(),
        bp::wrapper<Derived>() { };

    DerivedWrapper(const Derived derived) :
        Derived(derived),
        bp::wrapper<Derived>() { };

    void getString(bp::object pyObj) {
        std::string strLine = bp::extract<std::string>(pyObj);
        std::stringstream sstrLine;
        sstrLine<<"(from DerivedWrapper) "<<strLine;
        Derived::getString(sstrLine);
    }
};

[...]

    bp::class_<DerivedWrapper, bp::bases<Base> >("Derived")
        .def("getString", &DerivedWrapper::getString);

そして、の出力

base = testInheritance.Base()
base.getString("bla")

derived = testInheritance.Derived()
derived.getString("blub")

期待通りです

Got string: "bla"
Got string: "(from DerivedWrapper) blub"
于 2012-09-04T07:46:44.763 に答える
1

私は解決できたのとまったく同じ問題を抱えていましたが、いくつかの特別なケースでは解決策にいくつかの内部障害があります。boost::python によって渡された値から boost::weak_ptr 参照を作成する必要がある場合に、python で boost::shared_ptr を使用することに関する既知の問題があります。記事と関係ないので詳しくは割愛します。とにかく、boost::shared_ptr を別のクラス (PythonSharedPtr と呼びます) にラップして、boost::shared_ptr を boost::python から非表示にする必要があり、同様の問題が発生します。次の設定を検討してください: クラス A は c++ 側で boost::shared_ptr として使用され、クラス B (A から継承) は boost::shared_ptr として使用され、python では両方の shared_ptr が別のクラスにラップされます (詳細については、なぜそれを作成する必要があったのか、boost::python と weak_ptrで説明されています: 消えているもの http://mail.python.org/pipermail/cplusplus-sig/2009-November/014983.html

したがって、ブースト python への適切なエクスポートを記述する必要があります:

今まであなたのコードと似ていると思います。注意が必要なのは、boost::python で B をエクスポートするために base を使用できるようにする方法です (ただし、shared_ptr は shared_ptr とは関係ありません)。boost::python ソースでいくつかの調査を行った後、非常に優れたソリューションが付属していますが、クラス B の多重継承がない場合にのみ機能します。

コードは次のとおりです。

namespace boost { namespace python { namespace objects
{
    template<typename Source, typename Target>
    struct shared_ptr_cast_generator
    {
        static void* execute(void* source)
        {
            const boost::shared_ptr<Source>* sourcePtr = static_cast<boost::shared_ptr<Source>*>(source);
            const boost::shared_ptr<Target> target     = boost::dynamic_pointer_cast<Target>(*sourcePtr);
            if(reinterpret_cast<size_t>(target.get()) == reinterpret_cast<size_t>(sourcePtr->get()))
                return source;
            else
            {
                // assertion which is triggered when multi-inheritance is used for Source type
                // in this case it is necessary to create new instance of shared_ptr<Target> but
                // it is not possible to make it in-place due to memory leak
                assert(!"Wrong cast");
                return nullptr;
            }
        }
    };

    template<typename Source, typename Target>
    struct cast_generator<boost::shared_ptr<Source>, boost::shared_ptr<Target> >
    {
        typedef shared_ptr_cast_generator<Source, Target> type;
    };
}}}

このようなコードを提供することで、Python への 2 番目のエクスポートを調整することができます: class_、wrapped_shared_ptr、noncopyable、bases >

実行関数に格納された変換には注意してください。ソースとターゲットの間の変換が存在する場合、同じアドレスが返されます。そのため、ソース* をターゲット* に再解釈するだけでも有効でなければなりません (両方のクラスのデータはまったく同じ場所に格納する必要があります)。場所)。

あなたの場合、そのような解決策は十分ではないかもしれませんが、少なくともいくつかのアイデアを得ることができます.

于 2013-03-22T16:57:38.507 に答える