2015-04-23 2 views
0

Я столкнулся с еще одной проблемой в моем приключении Boost.Python.Boost.Python, неспособный разрешить производный тип, переданный функции

Я следующий модуль Python определены:

#include <Python.h> 
#include <iostream> 
#include <boost/python.hpp> 

using namespace boost; 
using namespace boost::python; 

struct Base { }; 

void foo(boost::shared_ptr<Base>) 
{ 
    std::cout << "yay\n"; 
} 

BOOST_PYTHON_MODULE(Test) 
{ 
    class_<Base, shared_ptr<Base>, noncopyable>("Base", init<>()); 

    def("foo", foo); 
} 

Запуск следующего сценария:

from Test import * 

class Bar(Base): 
    def __init__(self): 
     pass 

foo(Base()) #works 
foo(Bar()) #error 

Последняя строка дает ошибку эффекта этого:

Python argument types in 
    foo(Bar) 
did not match C++ signature: 
    foo(class boost::shared_ptr<struct Base>) 

Теперь мой вопрос: почему это не работает? Разумеется, система типов должна иметь возможность работать, Bar - это пример Base?

http://coliru.stacked-crooked.com/a/43f111fb3032a20a

Любая помощь приветствуется!

ответ

1

В этом конкретном случае сообщение об ошибке вводит в заблуждение. Функция получает аргумент с правом типа; однако аргумент имеет несоответствующее значение . Инициализатор Bar не инициализирует часть своей иерархии Python Base. Экземпляр Python не содержит boost::shared_ptr<Base> экземпляр, в результате чего Boost.Python не в состоянии направить на C++ функции:

class Bar(Base): 
    def __init__(self): 
     pass # Base is not initialized. 

fun(Base()) # No boost::shared_ptr<Base> instance. 

Чтобы решить эту проблему, явно вызывать Base.__init__() в Bar.__init__():

class Bar(Base): 
    def __init__(self): 
     Base.__init__(self) # Instantiates boost::shared_ptr<Base>. 

fun(Bar()) # Boost.Python will extract boost::shared_ptr<Base> from Bar(). 

Подробнее о Python, если производный класс определяет метод __init__(), тогда он должен явно вызвать метод родительского класса '__init__(). Документация Python states:

Если базовый класс имеет __init__() метод, __init__() метод производного класса, если таковые имеются, необходимо вызвать его для обеспечения надлежащей инициализации базового класса части экземпляра; например: BaseClass.__init__(self, [args...]).

В Boost.Python оболочки класса C++ имеют instance_holder. Эти объекты держать экземпляры C++ в их Python объект оболочки, и конкретизация объекта в C++ происходит в __init__ функции объекта в Python:

Когда __init__ функции для класса обернутого C++ вызывается, новый instance_holder экземпляр создаются и установлен в объекте Python [...]

Поэтому, если метод объекта Python в __init__() не вызывается, объект внутреннего C++ не будет экземпляр. Когда открытая функция C++ вызывается из Python, Boost.Python будет исследовать аргументы вызова, пытаясь идентифицировать соответствующую функцию C++ в рамках набора открытых функций.Если совпадение не найдено, оно вызывает исключение Boost.Python.ArgumentError, в котором перечислены типы аргументов и набор функций C++, для которых он не совпал.


Вот полный пример demonstrating, имеющий два различных типа Python наследовать от типа открытой C++, где одна иерархия инициализирован правильно, а другой нет:

#include <boost/python.hpp> 

struct base {}; 

void foo(boost::shared_ptr<base>) {} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::class_<base, boost::shared_ptr<base>, boost::noncopyable>(
     "Base", python::init<>()) 
    ; 

    python::def("foo", &foo); 
} 

Интерактивное использование:

>>> import example 
>>> class GoodDerived(example.Base): 
...  def __init__(self): 
...   example.Base.__init__(self) 
... 
>>> class BadDerived(example.Base): 
...  def __init__(self): 
...   pass 
... 
>>> assert(isinstance(GoodDerived(), example.Base)) 
>>> assert(isinstance(BadDerived(), example.Base)) 
>>> try: 
...  example.foo(GoodDerived()) 
...  got_exception = False 
... except: 
...  got_exception = True 
... finally: 
...  assert(not got_exception) 
... 
>>> try: 
...  example.foo(BadDerived()) 
...  got_exception = False 
... except: 
...  got_exception = True 
... finally: 
...  assert(got_exception) 

Обратите внимание, что хотя иерархия типов правильная и проверяемая с помощью isinstance((), типы не указывают, имеет ли экземпляр экземпляр надлежащее значение.

+0

Я попробую это, когда вернусь к своему компьютеру! –

+0

Ты спасатель, спасибо. –

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