2012-01-23 3 views
0

Хорошо, я уже задал два вопроса о своей проблеме и, несмотря на то, что ответы были действительно полезными, я не могу найти оптимальное решение для своей проблемы. Позвольте мне объяснить мою главную задачу/проблему сейчас.Реализация поддержки std :: vector без std_vector.i

Из-за некоторых ограничений я не могу использовать std_vector.i в моем интерфейсе swig, но мне нужно использовать объект C++ (вектор векторов строки) vector<vector<string>> в Python. Я реализовал решение, в котором я конвертирую весь код vector<vector<string> > в «Список списков» на Python, где я делаю следующие преобразования: каждая строка C++ для строки Python с использованием PyString_FromString() каждый vector<string> в списки Python l1, l2, l3, l4 ... и, наконец, vector<vector<string> > в список Python, содержащий элементы l1, l2, l3, l4 .. как элементы.

Хотя это решение отлично работает, и я могу получить доступ к строковым значениям в Python, но это решение не выглядит оптимальным для меня.

Я бы предпочел класс (без использования std_vector.i), чей объект я могу передать как аргумент функции, который будет заполнен значениями, и после возврата из функции я должен иметь доступ к значениям, используя ob[0][0] и т. Д. В этом я должен будет сделать только одно преобразование (строка C++ в строку python), для каждого доступного значения, в __getitem__. Но я не знаю, как определить класс, представляющий vector<vector<string> > в Python, без использования %template.

+0

его вектор вектор >. Я написал это в проблеме, но из-за какой-то неизвестной ошибки он показывает vector> вместо vector >. – Saurabh

+0

Здесь я не понимаю вопроса - вы хотите обернуть «std :: vector» без использования уже предоставленного интерфейса. Вы также говорите, что вы уже написали код для 'vector >' в список списка. Можете ли вы объяснить, с минимальным * примером, что вы хотите обернуть, и почему ни один из них не был бы разумным? – Flexo

+0

хорошо, я не использую уже поставляемый интерфейс i.e std_vector.i, потому что он недоступен в моей организации (мы используем собственные инструменты сборки и библиотеки, и поэтому мы не можем использовать std_vector.i). в настоящее время я делаю что-то вроде этого: % apply vector <вектор > * OUTPUT {vector > * result}; Тип карты (in, numinputs = 0) vector > * OUTPUT (вектор <вектор > t) { $ 1 = t; } typemap (argout, fragment = "t_output_helper") vector > * OUTPUT { $ result = t_output_helper ($ result, my_function_to_convert_vectorToList ($ 1)); } – Saurabh

ответ

1

Я собрал пример минимальной обертки для std::vector<std::vector<std::string > >, которая работает без каких-либо дополнительных SWIG-файлов (например, std_vector.i и std_string.i).

Я также собрать небольшой заголовочный файл, чтобы проверить свою реализацию с:

#include <vector> 
#include <string> 
#include <algorithm> 
#include <iterator> 
#include <iostream> 

inline void print_vec(const std::vector<std::string>& v) { 
    std::copy(v.begin(),v.end(), std::ostream_iterator<std::string>(std::cout, "\n")); 
} 

inline void print_vec_vec(const std::vector<std::vector<std::string> >& v) { 
    std::for_each(v.begin(),v.end(),print_vec); 
} 

std::vector<std::vector<std::string> > make() { 
    static std::vector<std::string> test1; 
    static std::vector<std::string> test2; 

    static std::vector<std::vector<std::string> > ret; 
    test1.push_back("hello"); 
    test2.push_back("world"); 
    test2.push_back("another"); 
    ret.push_back(test1); 
    ret.push_back(test2); 
    return ret; 
} 

Это самая маленькая реализация я мог думать о том, что полезно упражнения сгенерированного интерфейс.

Интерфейс SWIG, который я написал, дает определение скелета std::vector - достаточно, чтобы убедить SWIG на самом деле обернуть вещь. Мы также распространяем его на два случая, о которых мы заботимся, чтобы обеспечить реализацию __getitem__, минимальное требование для синтаксиса obj[x][y], который вы хотите использовать.

%module Test 

%{ 
#include "test.hh" 
%} 

namespace std { 
template <typename T> 
class vector { 
}; 
} 

%extend std::vector<std::vector<std::string> > { 
    std::vector<std::string> __getitem__(unsigned i) throw(std::out_of_range) { 
    return $self->at(i); 
    } 
} 

%extend std::vector<std::string> { 
    const char * __getitem__(unsigned i) throw(std::out_of_range) { 
    return $self->at(i).c_str(); 
    } 
} 

%template (VecString) std::vector<std::string>; 
%template (VecVecString) std::vector<std::vector<std::string> >; 

%include "test.hh" 

Там трюк там с c_str(), чтобы избежать включения std_string.i. Этот интерфейс позволяет мне делать такие вещи, как это в Python:

Python 2.7.1+ (r271:86832, Apr 11 2011, 18:05:24) 
[GCC 4.5.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import Test 
>>> t=Test.make() 
>>> print t[0][0] 
hello 
>>> 

В настоящее время не вызывает правильный тип исключения Python в __getitem__. Вы можете сделать это либо с %include "exception.i", либо с %exception и написать собственный try/catch около $action.

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

Это, вероятно, не быстрее, чем std_vector.i или ваша домашняя страница, которая напрямую преобразуется в список списка Python. В общем, хотя я не думаю, что это так, это хорошая идея - использование существующей реализации std_vector.i вместо того, чтобы изобретать колесо, кажется более логичным.

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