9

C++ コードベースの Python バインディングを構築する必要があります。私は boost::python を使用していますが、テンプレートを使用して返す関数を含むクラスを公開しようとして問題に遭遇しました。これが典型的な例です

class Foo 
{ 
    public: 
        Foo(); 
        template<typename T> Foo& setValue(
            const string& propertyName, const T& value); 
        template<typename T> const T& getValue(
            const string& propertyName); 
}; 

典型的な T は、string、double、vector です。

ドキュメントを読んだ後、使用するすべてのタイプに薄いラッパーを使用してみました。string と double のラッパーと、対応するクラス宣言を次に示します。

Foo & (Foo::*setValueDouble)(const std::string&,const double &) = 
    &Foo::setValue; 
const double & (Foo::*getValueDouble)(const std::string&) = 
    &Foo::getValue;

Foo & (Foo::*setValueString)(const std::string&,const std::string &) = 
    &Foo::setValue; 
const std::string & (Foo::*getValueString)(const std::string&) = 
    &Foo::getValue;

class_<Foo>("Foo") 
    .def("setValue",setValueDouble, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue",getValueDouble,
        return_value_policy<copy_const_reference>()) 
    .def("getValue",getValueString, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
        return_value_policy<reference_existing_object>());

正常にコンパイルされますが、Python バインディングを使用しようとすると、C++ 例外が発生します。

>>> f = Foo()  
>>> f.setValue("key",1.0) 
>>> f.getValue("key") 
Traceback (most recent call last): 
  File "<stdin>", line 1, in ? 
  RuntimeError: unidentifiable C++ exception

興味深いことに、ダブルまたは文字列値の Foo のみを公開すると、つまり

class_<Foo>("Foo") 
    .def("getValue",getValueString, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue",setValueString, 
        return_value_policy<reference_existing_object>());

それは正常に動作します。何か不足していますか?

4

3 に答える 3

3

これはあなたの問題に直接関係していないかもしれませんが、そのようなテンプレートでの関数シグネチャのキャストは信頼できません。私はそれを次のようにラップしたでしょう:

class_<Foo>("Foo") 
    .def("setValue", &Foo::setValue<double>, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue", &Foo::getValue<double>,
        return_value_policy<copy_const_reference>()) 
    .def("getValue", &Foo::getValue<std::string>, 
        return_value_policy<copy_const_reference>()) 
    .def("setValue", &Foo::setValue<std::string>, 
        return_value_policy<reference_existing_object>());

それが機能しない場合は、いくつかのシム関数を作成する必要がある場合があります。

Foo& setValueDouble(foo& self, const string& propertyName, const double value)
{ 
    return self.setValue(propertyName, value)
}
...

それらがメンバー関数であると考えられるようにそれらをエクスポートします。

複数の関数オーバーロードを同じ名前にエクスポートすることは、Boost::Python で行うのに完全に有効であるため、それが問題だとは思いません。

于 2011-01-31T16:33:12.547 に答える
0

boost :: python :: objectを返す/取得するゲッター/セッター用のC++ラッパーを作成するのはどうですか?次に、C ++ラッパーで取得したタイプを判別し、boost :: python::objectにラップ/アンラップします。

struct FooWrap : public Foo
{
    using boost::python;
    Foo& setValueO(const string& propertyName, const object& obj)
    {
        object value;
        if(PyInt_Check(obj.ptr())) {
            return setValue<int>(propertyName, extract<int>(obj);
        } else if(PyFloat_Check(obj.ptr())) {
            return setValue<double>(propertyName, extract<double>(obj);
        } else if(PyString_Check(obj.ptr())) {
            return setValue<std::string>(propertyName, extract<std::string>(obj);
        }
        // etc...
    }

    object getValueO(const std::string& propertyName)
    {
        if(determineType() == TYPE_INT) { // however you determine the type
            return object(getValue<int>(propertyName));
        } else if(determineType() == TYPE_DOUBLE)   {
            return object(getValue<double>(propertyName));
        } else if(determineType() == TYPE_STRING)   {
            return object(getValue<std::string>(propertyName));
        }
        // etc...
    }
};

class_<Foo>("Foo") 
    .def("setValue", &FooWrap::setValueO, 
        return_value_policy<reference_existing_object>()) 
    .def("getValue", &FooWrap::getValueO,
        return_value_policy<copy_const_reference>()) 
于 2011-02-28T05:16:17.187 に答える
0

問題は、boost::python が「getValue」に対してどのオーバーロードを呼び出すかを認識していないことだと思われます。getValueDouble または getValueString を呼び出す必要がありますか? それらを getValueString および getValueDouble (メソッド名として) として明示的にバインドすると、うまくいくに違いありません。

于 2011-01-30T19:01:13.670 に答える