2013-11-26 4 views
3

Я написал часть класса на C++, и я хочу использовать его совместно с графическим интерфейсом Python, поэтому я использую Boost.Python, чтобы попробовать и сделать это легко. Проблема я бегу в том, что в следующем их руководство (http://www.boost.org/doc/libs/1_55_0/libs/python/doc/tutorial/doc/html/python/exposing.html), я получаю следующее исключение всякий раз, когда я бегу bjam:Boost.Python 'слишком мало аргументов шаблона для class_'

PacketWarrior/pcap_ext.cc:21:5: error: too few template arguments for class template 'class_' 

Очевидно, что жалуется на меня, опуская то, что они утверждают, являются необязательными аргументами к функции шаблона 'class_', но я не могу понять, почему. Я предполагаю, что это проблема с компилятором, но я не знаю, как это исправить. Я запускаю OS X 10.9 и использую darwin для набора инструментов по умолчанию, но GCC выдает ту же ошибку. Моя Boost версия 1_55_0, если это вообще помогает.

заголовка файла класса (охранники заголовка опущены):

#include <queue> 
#include "pcap.h" 

#include "Packet.h" 

class PacketEngine { 

public: 
    PacketEngine(); 
    ~PacketEngine(); 

    const char** getAvailableDevices(char *error_buf); 
    bool selectDevice(const char* dev); 
    Packet getNextPacket(); 

private: 
    char *selected_device; 
    char **devices; 
    int num_devices; 
    std::queue<Packet> packet_queue; 
}; 

сс файл, содержащий ссылки на Boost.Python и мой класс:

#include <boost/python/module.hpp> 
#include <boost/python/def.hpp> 
#include "PacketEngine.h" 

BOOST_PYTHON_MODULE(pcap_ext) { 
    using namespace boost::python; 

    class_<PacketEngine>("PacketEngine") 
     .def("getAvailableDevices", &PacketEngine::getAvailableDevices); 
} 

И мой файл bjam (нерелевантные части и комментарии опущены):

use-project boost : ../../../Downloads/boost_1_55_0 ; 

project 
    : requirements <library>/boost/python//boost_python 
       <implicit-dependency>/boost//headers 
    : usage-requirements <implicit-dependency>/boost//headers 
    ; 

python-extension pcap_ext : PacketWarrior/pcap_ext.cc ; 

install convenient_copy 
    : pcap_ext 
    : <install-dependencies>on <install-type>SHARED_LIB <install-type>PYTHON_EXTENSION 
    <location>. 
    ; 

local rule run-test (test-name : sources +) 
{ 
    import testing ; 
    testing.make-test run-pyd : $(sources) : : $(test-name) ; 
} 

run-test pcap : pcap_ext pcap.py ; 

Любые идеи относительно того, как обойти это исключение, отличные я оценил! Я рассмотрел очевидный маршрут добавления дополнительных параметров, но я не думаю, что они имеют отношение к моему проекту. Определение class_ можно найти здесь:

http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/class.html

+0

Если вы отметите свой вопрос с [тегом: буст-питон], вы максимизировать ваш шансы привлечь к работе некоторых экспертов по библиотеке. Я очень мало знаю об этом, но быстрый поиск в Google привел меня к [этому] (http://lists.boost.org/boost-users/2008/07/37787.php), и это кажется многообещающим. – llonesmiz

+0

сделаю, спасибо за отзыв – drodman

ответ

1

Короче говоря, включает в себя также:

  • boost/python.hpp: файл удобного заголовка Boost.Python.
  • boost/python/class.hpp: Заголовок, который определяет boost::python::class_.

Входящие в заголовочные файлы объявляют class_ без аргументов шаблона по умолчанию от def_visitor.hpp.


Кроме того, пытаясь непосредственно подвергать PacketEngine::getAvailableDevices(), скорее всего, представляет собой проблему:

  • Он принимает char* аргумент, но строки являются неизменными в Python.
  • Нет типов, которые автоматически конвертируются в/из const char** в Boost.Python.

Это может быть разумным для пользователя Python ожидать PacketEngine.getAvailableDevices() вернуть итератор типа, содержащий Python str с, или выбросить исключение ошибки. Это может быть выполнено неинтрузивным способом, написав вспомогательную или вспомогательную функцию, которая делегирует оригинальную функцию, но подвергается Python как PacketEngine.getAvailableDevices().

Вот полный пример, основанный на исходном коде:

#include <exception> // std::runtime_error 
#include <boost/python.hpp> 

namespace { 
const char* devices_str[] = { 
    "device A", 
    "device B", 
    "device C", 
    NULL 
}; 
} // namespace 

class PacketEngine 
{ 
public: 
    PacketEngine() : devices(devices_str) {} 

    const char** getAvailableDevices(char *error_buf) 
    { 
    // Mockup example to force an error on second call. 
    static bool do_error = false; 
    if (do_error) 
    { 
     strcpy(error_buf, "engine not responding"); 
    } 
    do_error = true; 
    return devices; 
    } 

private: 
    const char **devices; 
}; 

/// @brief Auxiliary function for PacketEngine::getAvailableDevices that 
///  provides a more Pythonic API. The original function accepts a 
///  char* and returns a const char**. Both of these types are 
///  difficult to use within Boost.Python, as strings are immutable 
///  in Python, and Boost.Python is focused to providing 
///  interoperability to C++, so the const char** type has no direct 
///  support. 
boost::python::list PacketEngine_getAvailableDevices(PacketEngine& self) 
{ 
    // Get device list and error from PacketEngine. 
    char error_buffer[256] = { 0 }; 
    const char** devices = self.getAvailableDevices(error_buffer); 

    // On error, throw an exception. Boost.Python will catch it and 
    // convert it to a Python's exceptions.RuntimeError. 
    if (error_buffer[0]) 
    { 
    throw std::runtime_error(error_buffer); 
    } 

    // Convert the c-string array to a list of Python strings. 
    namespace python = boost::python; 
    python::list device_list; 
    for (unsigned int i = 0; devices[i]; ++i) 
    { 
    const char* device = devices[i]; 
    device_list.append(python::str(device, strlen(device))); 
    } 
    return device_list; 
} 

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

    python::class_<PacketEngine>("PacketEngine") 
    .def("getAvailableDevices", &PacketEngine_getAvailableDevices); 
} 

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

>>> import example 
>>> engine = example.PacketEngine() 
>>> for device in engine.getAvailableDevices(): 
...  print device 
... 
device A 
device B 
device C 
>>> devices = engine.getAvailableDevices() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: engine not responding 
+0

Большое вам спасибо! Мне было интересно разоблачить char **, мне придется читать в Python поддерживаемые типы C++ немного больше – drodman

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