2017-01-11 21 views
0

Я пытаюсь выставить свои классы C++ на Python с помощью Boost.Python. Вот simplyfied версия о том, что я пытаюсь сделать:ТипError: нет конвертера to_python (по значению) для типа C++

struct Base { 
    virtual ~Base() {}; 
    virtual char const *Hello() { 
     printf("Base.Hello\n"); 
     return "Hello. I'm Base."; 
    }; 
}; 

struct Derived : Base { 
    char const *Hello() { 
     printf("Derived.Hello\n"); 
     return "Hello. I'm Derived."; 
    }; 

    Base &test() { 
     printf("Derived.test\n"); 
     // ... 
     // After some calculation, we get result reference `instance' 
     // `instance' can be an instance of Base or Derived. 
     // ... 
     return instance; 
    } 
}; 

Я хочу использовать выше классы следующим образом в Python:

instance = Derived() 

// If method test returns an instance of Base 
instance.test().Hello() // Result: "Hello. I'm Base." 

// If method test returns an instance of Derived 
instance.test().Hello() // Result: "Hello. I'm Derived." 

Я не знаю ни одного красивого решения этой проблемы , Я просто попытался это:

struct BaseWrapper : Base, wrapper<Base> { 
    char const *Hello() { 
     printf("BaseWrapper.Hello\n"); 
     if (override Hello = this->get_override("Hello")) { 
      return Hello(); 
     } 
     return Base::Hello(); 
    } 

    char const *default_Hello() { 
     printf("BaseWrapper.default_Hello\n"); 
     return this->Base::Hello(); 
    } 
}; 

struct DerivedWrapper : Derived, wrapper<Derived> { 
    char const *Hello() { 
     printf("DerivedWrapper.Hello\n"); 
     if (override Hello = this->get_override("Hello")) { 
      return Hello(); 
     } 
     return Derived::Hello(); 
    } 

    char const *default_Hello() { 
     printf("DerivedWrapper.default_Hello\n"); 
     return this->Derived::Hello(); 
    } 

    Base &test() { 
     printf("DerivedWrapper.test\n"); 
     if (override Hello = this->get_override("test")) { 
      return Hello(); 
     } 
     return Derived::test(); 
    } 

    Base &default_test() { 
     printf("DerivedWrapper.default_test\n"); 
     return this->Derived::test(); 
    } 
}; 

И их, я использую следующий код:

BOOST_PYTHON_MODULE(Wrapper) { 
    class_<BaseWrapper, boost::noncopyable>("Base") 
       .def("Hello", &Base::Hello, &BaseWrapper::default_Hello); 

    class_<DerivedWrapper, boost::noncopyable, bases<Base> >("Derived") 
      .def("Hello", &Derived::Hello, &DerivedWrapper::default_Hello) 
      .def("test", &Derived::test, return_value_policy<copy_non_const_reference>()); 
} 

Но когда я скомпилированный выше кода в .so файл, и используется в питона

derived = Wrapper.Derived() 
derived.test() 

Он исключает исключение:

TypeError: No to_python (by-value) converter found for C++ type: Base 
  1. Этот пост имеет ту же ошибку, что и у меня, но по-другому это мне не очень помогло. Boost.Python call by reference : TypeError: No to_python (by-value) converter found for C++ type:

  2. Этот пост решает аналогичную проблему, но мне тоже не помогло. https://github.com/BVLC/caffe/issues/3494

У меня есть две проблемы:

  1. Если так, как я пытался это правильный путь, как решить эту проблему TypeError?
  2. Если я попробовал неправильный путь, тогда какой лучший способ решить проблему с помощью boost.python?

ответ

0

Этот код работает для меня:

struct Base { 
    virtual ~Base() {}; 
    virtual char const *hello() { 
     return "Hello. I'm Base."; 
    }; 
}; 

struct Derived : Base { 
    char const *hello() { 
     return "Hello. I'm Derived."; 
    }; 

    Base &test(bool derived) { 
     static Base b; 
     static Derived d; 
     if (derived) { 
      return d; 
     } else { 
      return b; 
     } 
    } 
}; 

BOOST_PYTHON_MODULE(wrapper) 
{ 
    using namespace boost::python; 
    class_<Base>("Base") 
     .def("hello", &Base::hello) 
     ; 

    class_<Derived, bases<Base>>("Derived") 
     .def("test", &Derived::test, return_internal_reference<>()) 
     ; 
} 

Тестирование модуля:

>>> import wrapper 
>>> d = wrapper.Derived() 
>>> d.test(True).hello() 
"Hello. I'm Derived." 
>>> d.test(False).hello() 
"Hello. I'm Base." 
>>> 
+0

Спасибо за ваше решение, она решить мою проблему. Я также нашел руководство: [link] (http://www.boost.org/doc/libs/1_45_0/libs/python/doc/v2/return_internal_reference.html) –