2009-10-15 3 views
10

Я использую Boost.Python для создания модулей Python из классов C++. И я столкнулся с проблемой со ссылками.Boost.Python - Как вернуться по ссылке?

Включите следующий случай, когда у меня есть класс Foo с перегруженными методами get, которые могут либо возвращаться по значению, либо по ссылке.

Задание того, что нужно использовать возвращаемое значение, было легко, как только я набрал подпись. Но я думаю, что также возможно вернуть ссылку, используя return_value_policy. Однако, используя то, что казалось подходящим (doc); return_value_policy<reference_existing_object>, похоже, не работает.

Я не понял, что он делает?

struct Foo { 
    Foo(float x) { _x = x; } 
    float& get() { return _x; } 
    float get() const { return _x; } 
private: 
    float _x; 
}; 

// Wrapper code 
BOOST_PYTHON_MODULE(my_module) 
{ 
    using namespace boost::python; 
    typedef float (Foo::*get_by_value)() const; 
    typedef float& (Foo::*get_by_ref)(); 

    class_<Foo>("Foo", init<float>()) 
     .def("get", get_by_value(&Foo::get)) 
     .def("get_ref", get_by_ref(&Foo::get), 
      return_value_policy<reference_existing_object>())//Doesn't work 
     ; 
} 

Примечание: Я знаю, что может быть опасно ссылаться на существующий объект без управления жизненным циклом.

Update:
Похоже, что он работает для объектов, но не основные типы данных.
Возьмите этот пересмотренный пример:

struct Foo { 
    Foo(float x) { _x = x; } 
    float& get() { return _x; } 
    float get() const { return _x; } 
    void set(float f){ _x = f;} 
    Foo& self(){return *this;} 
private: 
    float _x; 
}; 

// Wrapper code 
using namespace boost::python; 
BOOST_PYTHON_MODULE(my_module) 
{ 
    typedef float (Foo::*get_by_value)() const; 

    class_<Foo>("Foo", init<float>()) 
     .def("get", get_by_value(&Foo::get)) 
     .def("get_self", &Foo::self, 
      return_value_policy<reference_existing_object>()) 
     .def("set", &Foo::set); 
     ; 
} 

Который в тесте дали ожидаемый результат:

>>> foo1 = Foo(123) 
>>> foo1.get() 
123.0 
>>> foo2 = foo1.get_self() 
>>> foo2.set(1) 
>>> foo1.get() 
1.0 
>>> id(foo1) == id(foo2) 
False 

ответ

7

В Python, есть понятие неизменных типов. Неизменяемый тип не может изменить его значение. Примерами встроенных неизменяемых типов являются int, float и str.

Сказав это, вы не можете делать то, что хотите, с помощью boost::python, поскольку сам Python не позволяет изменять значение поплавка, возвращаемого функцией.

Вашего второй пример показывает одно решение, другое будут создавать тонкие-обертки и обнажая, что:

void Foo_set_x(Foo& self, float value) { 
    self.get() = value; 
} 

class_<Foo>("Foo", init<float>()) 
    ... 
    .def("set", &Foo_set_x); 
; 

Что является лучшим решением, чем необходимость изменить исходные C++ класса.

0

Я много о Boost.Python не знаю, так что я может неправильно понять вопрос, в котором Это совершенно бесполезно. Но здесь идет:

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

У вас просто есть объекты, и у вас есть имена для этих объектов. Так

foo = "ryiuy" 

Создает строку объекта «ryiuy», а затем позволяет ссылаться на этот объект строки с именем «Foo». Поэтому в Python, когда вы что-то передали, вы передаете этот объект. В этом нет «значений», поэтому вы не можете передать значение. Но опять же, это также верная точка зрения, что нет ссылок, просто объектов и их имен.

Таким образом, я полагаю, что, когда вы получаете ссылку на C, вам нужно передать ссылку на объект, ссылки на ссылки на Python. И когда вы получаете значение на C, вам нужно передать ссылку на объект, который вы создаете из этого значения, на Python.

+0

Да, я знаю, что все ссылки в Python. Когда я создаю метод python с Boost.Python, который возвращает «по значению», он возвращает копию этого типа. То, что я хочу сделать, это * не * копировать, а вместо этого создать ссылку на тот же экземпляр. – mandrake

0

Вы уверены, что объект C++ копируется? Каждый раз вы будете получать новый объект python, но который ссылается на один и тот же объект C++. Как вы определяете, что объект был скопирован?

+0

Он не компилируется, когда я пытаюсь использовать ссылки. Как определить, легко ли ссылки или копии. Создайте две ссылки на то, что вы думаете, это один и тот же объект, измените его и посмотрите, появляются ли изменения в другом. (использование id (obj) не будет работать). – mandrake

+0

Да, просил проверить, что вы не используете id(). Какая ошибка компиляции? – Ben

+0

Это boost :: STATIC_ASSERTION_FAILURE, что указывает на то, что что-то я делаю либо не поддерживается, либо незаконно. Я просто не знаю, что. – mandrake

2

Я думаю, вы хотите return internal reference вместо этого. Я использовал его раньше, чтобы сделать что-то подобное.

Edit: Latest doc

+0

Это та же сделка. Он работает с объектами, но не с базовыми типами данных. – mandrake

+0

ссылка на документацию предназначена для версии 1.38, которая очень старая, начиная с этого комментария (1.61 - текущий) – ofloveandhate

Смежные вопросы