2013-09-25 2 views
1

Я попытался выяснить, как поддерживать const wchar_t * в качестве возвращаемого типа для функции, открытой в boost python. Моя версия boost - 1.52, и я работаю с python 2.7, если это имеет значение.Преобразование const wchar_t * в строку python в boost python

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

Вот мой тривиальный нерабочий пример:

#include <string> 
#include <boost/python.hpp> 
using namespace boost::python; 


struct wchar_t_to_python_str 
{ 
    static PyObject* convert(const wchar_t*) 
    { 
     std::string s = "I'm more interested in the function signature than how to do wide char to non-wide char conversion"; 
     return boost::python::incref(boost::python::object(s).ptr()); 
    } 
}; 


void init_module() 
{ 
    to_python_converter<const wchar_t*, wchar_t_to_python_str>(); 
} 

const wchar_t* testWchar() { 
    return L"Hello World"; 
} 
const char* testChar() { 
    return "Hello World"; 
} 

BOOST_PYTHON_MODULE(test) 
{ 
    // This works nicely, const char* is supported 
    def("testChar", testChar); 

    // This doesn't work, fails with this error 
    // 'awBoost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<T>' 
    // def("testWchar", testWchar); 

    // Throwing in a return value policy fires a compile time assert make_instance_impl 
    // BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >)); 
    // It seems like it gets confused by wchar_t not being a class, but it's hard to know 
    def("testWchar", testWchar, return_value_policy<reference_existing_object>()); 
} 

ответ

2

Есть несколько факторов, к этой проблеме:

  • Функции преобразования позволили с to_python_converter являются время выполнения преобразования.
  • Boost.Python не предоставляется builtin conversion поддержка wchar*. Возможно, это было упущено, поскольку добавлена ​​поддержка std::wstring, когда Boost.Python был обновлен для поддержки Python 3. Отсутствие встроенной поддержки преобразования заставляет внутренний класс требовать соответствующего CallPolicy во время компиляции. Ни одна из предоставленных моделей ResultConverterGenerator не является кандидатом на это преобразование, поскольку они в основном влияют на владение объектами/срок службы, а не тип конверсий.

Есть два подхода, которые работают в рамках этих ограничений:

  • Создать тип политики для обработки пользовательских wchar*, реализующих ResultConverterGenerator Concept.
  • Оберните функцию, возвращающую wchar*, с типом, который возвращает std::wstring.

Ниже приведен полный пример, демонстрирующий оба этих подхода:

#include <string> 
#include <boost/function_types/parameter_types.hpp> 
#include <boost/python.hpp> 

/// @brief ResultConverterGenerator used to transform wchar_t to PyObject. 
struct wchar_result_converter 
{ 
    template <class T> struct apply 
    { 
    struct type 
    { 
     /// @brief Convert wchar_t to PyObject. 
     PyObject* operator()(const wchar_t* str) const 
     { 
     // Using the Python/C API may be slighly cleaner. 
     return PyUnicode_FromWideChar(str, wcslen(str)); 

     // Alternatively, Boost.Python's object type can be used. While 
     // Boost.Python does not know how to convert wchar_t to an object, 
     // it does know how to convert std::wstring, so construct 
     // a temporary to help in the conversion. 
     // return boost::python::incref(
     //  boost::python::object(std::wstring(str)).ptr()); 
     } 

     /// @brief Used for documentation. 
     const PyTypeObject* get_pytype() const { return 0; } 
    }; // struct type 
    }; // struct apply 
}; 

/// @brief Modify the return type of a function using supplied CallPolicies. 
template <typename ReturnType, typename Fn, typename Policy> 
boost::python::object return_as(Fn fn, const Policy& policy) 
{ 
    // Build MPL type representing signature of function, injecting the 
    // explicitly provided return type. 
    typedef typename boost::mpl::push_front< 
    typename boost::function_types::parameter_types<Fn>::type, 
    ReturnType 
    >::type signature_type; 

    return boost::python::make_function(fn, policy, signature_type()); 
} 

/// @brief Modify the return type of a function using default_call_policies. 
template <typename ReturnType, typename Fn> 
boost::python::object return_as(Fn fn) 
{ 
    return return_as<ReturnType>(fn, boost::python::default_call_policies()); 
} 

// Test functions. 
const char* testChar() { return "Hello World"; } 
const wchar_t* testWchar() { return L"Hello World"; } 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 

    // Expose non-wide test char support. 
    python::def("testChar", testChar); 

    // Expose wide char support by: 
    // - providing a policy to convert the return value. 
    // - manipulating the return type. 
    python::def("testWchar1", &testWchar, 
       python::return_value_policy<wchar_result_converter>()); 
    python::def("testWchar2", return_as<std::wstring>(&testWchar)); 
} 

И его использование:

>>> import example 
>>> a = example.testChar() 
>>> print a 
Hello World 
>>> print type(a) 
<type 'str'> 
>>> b = example.testWchar1() 
>>> print b 
Hello World 
>>> print type(b) 
<type 'unicode'> 
>>> c = example.testWchar2() 
>>> print c 
Hello World 
>>> print type(c) 
<type 'unicode'> 
+0

Спасибо. Мне удалось запустить первую версию (с return_value_policy), которая, по сути, мне нужна, чтобы двигаться дальше. Я получил неприятную ошибку компиляции boost для второго подхода в visual studio 2012, который мне не удалось разобрать. – Laserallan

+0

Ошибка в случае, если кто-то хорош при boost :: mpl debugging: ошибка C3083: 'function_types': символ слева от '::' должен быть типом для строки typedef typename boost :: mpl :: push_front < typename boost :: function_types :: parameter_types :: type, ReturnType > :: type signature_type – Laserallan

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