Boost :: python Предоставление функций C ++ с использованием и возвращением шаблонов - PullRequest
9 голосов
/ 30 января 2011

Мне нужно построить привязки Python для кодовой базы C ++.Я использую 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 и соответствующее объявление класса.

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

Работает нормально.Я что-то упустил?

Ответы [ 3 ]

3 голосов
/ 31 января 2011

Возможно, это не связано с вашей проблемой напрямую, но я бы не стал доверять приведению сигнатур функций с подобными шаблонами. Я бы обернул это так:

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, поэтому я не думаю, что это проблема.

0 голосов
/ 28 февраля 2011

Как насчет создания оболочек C ++ для методов получения / установки, которые возвращают / принимают boost :: python :: object?Затем вы можете просто определить тип, который вы получили в вашей оболочке 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>()) 
0 голосов
/ 30 января 2011

Я подозреваю, что проблема в том, что boost :: python не знает, какую перегрузку вызывать для getValue - должен ли он вызывать getValueDouble или getValueString? Если вы связываете их явно как getValueString и getValueDouble (как имя метода), держу пари, это будет работать.

...