Как правильно обернуть std:: vector с SWIG для Python? Проблемы с std:: размер t

я пытаюсь сделать std::vector<std::size_t> для работы с SWIG. Мне нужно предоставить интерфейс python для библиотеки c++. std::vectors примитивных типов и объектов работают нормально, но есть проблема с std::size_t.

я предоставляю MCVE на github здесь.

главная проблема

в основном проблема в том, что std::size_t не признала и std::vector<std::size_t> трактуется как std::vector< int,std::allocator< int > > *. Когда я пытаюсь указать шаблон, я получаю следующий.

используя %template(VecSize) std::vector<std::size_t>; выдает:

swig -c++ -python c_swig_vec_std_size.i
:0: Warning(490): Fragment 'SWIG_AsVal_std_size_t' not found.
:0: Warning(490): Fragment 'SWIG_From_std_size_t' not found.
g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
c_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
c_swig_vec_std_size_wrap.cxx:4289: error: ‘SWIG_AsVal_std_size_t’ was not declared in this scope
c_swig_vec_std_size_wrap.cxx: In static member function ‘static PyObject* swig::traits_from<long unsigned int>::from(const swig::traits_from::value_type&)’:
c_swig_vec_std_size_wrap.cxx:4295: error: ‘SWIG_From_std_size_t’ was not declared in this scope
make: *** [c] Error 1

Минимальный Пример

пример C++ класс

следующий класс достаточно, чтобы показать функциональность, которая мне нужна. The std::vector<int> включается, чтобы показать предполагаемое поведение.

class_vec_std_size.ГЭС

#ifndef STD_SIZE_VEC
#define STD_SIZE_VEC

#include <vector>

class StdSizeVec{

public:
  StdSizeVec(){
    _myVec = std::vector<std::size_t>();
    _myVec.push_back(1);
    _myVec.push_back(2);

    _myInts = std::vector<int>();
    _myInts.push_back(1);
    _myInts.push_back(2);
  }

  ~StdSizeVec(){
    _myVec.clear();
  }

  inline std::vector<std::size_t> getValues(){
    return _myVec;
  }

  inline std::vector<int> getInts(){
    return _myInts;
  }

private:
  std::vector<std::size_t> _myVec;
  std::vector<int> _myInts;
};
#endif

различные попытки интерфейса

a_swig_vec_std_size.я!--48-->
%module a_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "class_vec_std_size.hpp"

выход

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from a_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t > *' at 0x2ad7047be330>
>>> ints = ssv.getInts()
>>> ints
<Swig Object of type 'std::vector< int > *' at 0x2ad7047be780>
>>> exit()
swig/python detected a memory leak of type 'std::vector< int > *', no destructor found.
swig/python detected a memory leak of type 'std::vector< std::size_t > *', no destructor found.
[paul@login-0-0 stack_swig]$

это основной наивный подход. Указатели не полезны в python, и есть сообщения об утечке памяти, которые мы не можем предоставить пользователям интерфейса.

b_swig_vec_std_size.я!--48-->
%module b_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%include "class_vec_std_size.hpp"

выход

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from b_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2aee17458330>
>>> ints = ssv.getInts()
>>> ints
<Swig Object of type 'std::vector< int,std::allocator< int > > *' at 0x2aee17458930>
>>> exit()
swig/python detected a memory leak of type 'std::vector< int,std::allocator< int > > *', no destructor found.
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.

используя правильный "std_vector.i", SWIG знает больше о векторе и распределителях, но все же эти указатели не полезны для клиентского кода в python, и есть ошибка утечки памяти сообщения.

c_swig_vec_std_size.я!--48-->

этот интерфейс использует правильно %template директивы, как ответ. Здесь SWIG не понимает std::size_t в качестве аргумента шаблона.

%module c_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

// Does not compile
//%template(VecSize) std::vector<std::size_t>;
//
// Gives the following errors
//swig -c++ -python c_swig_vec_std_size.i
// :0: Warning(490): Fragment 'SWIG_AsVal_std_size_t' not found.
// :0: Warning(490): Fragment 'SWIG_From_std_size_t' not found.
// g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
// c_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
// c_swig_vec_std_size_wrap.cxx:4289: error: ‘SWIG_AsVal_std_size_t’ was not declared in this scope
// c_swig_vec_std_size_wrap.cxx: In static member function ‘static PyObject* swig::traits_from<long unsigned int>::from(const swig::traits_from::value_type&)’:
// c_swig_vec_std_size_wrap.cxx:4295: error: ‘SWIG_From_std_size_t’ was not declared in this scope
// make: *** [c] Error 1

//The following compiles but does not work
%template(VecSize) std::vector<size_t>;

%include "class_vec_std_size.hpp"

выход

[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from c_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2b286104bd80>
>>> ints = ssv.getInts()
>>> ints
(1, 2)
>>> exit()
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.

теперь std::vector<int> работает нормально, но (без std::) не делает работу.

некоторые интернет-рытье

я нашел несколько сообщений, которые предлагают некоторые ключи.

ощущение этой нашел 2006 сообщение с той же проблемой

на std::vector:: size_type обернутый как указатель не целое число ссылка имела некоторую полезную информацию, но проблема не совсем то же самое.

я нашел это примитивы.я!--37--> от Магнума.fe проект, но думать желаемое и импорт примитивы.я!--95--> у меня не получилось.

после что я пытался реализовать SWIG_AsVal_std_size_t и SWIG_From_std_size_t похоже на их подход, но не повезло.

ручной прокат std_size_t.я!--48-->
%fragment("SWIG_From_std_size_t", "header", fragment=SWIG_From_frag(std::size_t))
{
  SWIGINTERNINLINE PyObject * SWIG_From_std_size_t(std::size_t value)
  {
    return PyInt_FromSize_t(value);
  }
}


%fragment("SWIG_AsVal_std_size_t", "header")
{

SWIGINTERNINLINE bool SWIG_AsVal_std_size_t(PyObject* in, std::size_t& value)
{

  // Get integer type
  if(PyInt_Check(in)){
    long unsigned int long_uint = PyLong_AsLong(in);
    value = static_cast<std::size_t>(long_uint);
    return true;
  }else{
    return false;
  }

}
}

%fragment(SWIG_From_frag(std::size_t));
%fragment("SWIG_AsVal_std_size_t");

это было импортировано в d_swig_vec_std_size.я!--95-->. но он не компилируется.

%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"
%template(VecSize) std::vector<std::size_t>;

%include "class_vec_std_size.hpp"

вот, я понял.

swig -c++ -python d_swig_vec_std_size.i
g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
d_swig_vec_std_size_wrap.cxx: In static member function ‘static int swig::traits_asval<long unsigned int>::asval(PyObject*, swig::traits_asval::value_type*)’:
d_swig_vec_std_size_wrap.cxx:4311: error: invalid initialization of reference of type ‘size_t&’ from expression of type ‘swig::traits_asval::value_type*’
d_swig_vec_std_size_wrap.cxx:4288: error: in passing argument 2 of ‘bool SWIG_AsVal_std_size_t(PyObject*, size_t&)’
make: *** [d] Error 1

make-файл

PYTHON=/public/users/paul/dev/software/Python-2.7.11

all: a b c d

a:
    swig -c++ -python a_swig_vec_std_size.i
    g++ -fpic -c a_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared a_swig_vec_std_size_wrap.o -o _a_swig_vec_std_size.so

b:
    swig -c++ -python b_swig_vec_std_size.i
    g++ -fpic -c b_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared b_swig_vec_std_size_wrap.o -o _b_swig_vec_std_size.so

c:
    swig -c++ -python c_swig_vec_std_size.i
    g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared c_swig_vec_std_size_wrap.o -o _c_swig_vec_std_size.so

d:
    swig -c++ -python d_swig_vec_std_size.i
    g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I${PYTHON}/Include -I${PYTHON}
    g++ -g -fpic -shared d_swig_vec_std_size_wrap.o -o _d_swig_vec_std_size.so


clean: clean_a clean_b clean_c clean_d

clean_a:
    rm a_swig_vec_std_size_wrap.cxx a_swig_vec_std_size.py a_swig_vec_std_size_wrap.o _a_swig_vec_std_size.so

clean_b:
    rm b_swig_vec_std_size_wrap.cxx b_swig_vec_std_size.py b_swig_vec_std_size_wrap.o _b_swig_vec_std_size.so

clean_c:
    rm c_swig_vec_std_size_wrap.cxx c_swig_vec_std_size.py c_swig_vec_std_size_wrap.o _c_swig_vec_std_size.so

clean_d:
    rm d_swig_vec_std_size_wrap.cxx d_swig_vec_std_size.py d_swig_vec_std_size_wrap.o _d_swig_vec_std_size.so

Программы

python version: Python 2.7.11
g++ version: g++ (GCC) 4.4.7
swig version: SWIG Version 1.3.40

использование более новой версии swig (swig-3.0.10) дает тот же результат для мне.

резюме

я подозреваю, что ответ может быть по линиям интерфейса dstd::size_t реализуется по-разному в зависимости от архитектуры вместо того, чтобы иметь фиксированный размер. В любом случае, я ожидал, что SWIG сможет справиться с этим. Я что-то упускаю? Я хотел бы найти решение, которое не требует внесения изменений в библиотеку C++ (например, инкапсуляции std:: size_t в struct или через int вместо).

попытка решения Йенса Монка

namespace std {
    %template(VecSize) vector<size_t>;
}

я понимаю:

[paul@login-0-0 stack_swig]$ make clean
rm a_swig_vec_std_size_wrap.cxx a_swig_vec_std_size.py a_swig_vec_std_size_wrap.o _a_swig_vec_std_size.so
rm b_swig_vec_std_size_wrap.cxx b_swig_vec_std_size.py b_swig_vec_std_size_wrap.o _b_swig_vec_std_size.so
rm c_swig_vec_std_size_wrap.cxx c_swig_vec_std_size.py c_swig_vec_std_size_wrap.o _c_swig_vec_std_size.so
rm d_swig_vec_std_size_wrap.cxx d_swig_vec_std_size.py d_swig_vec_std_size_wrap.o _d_swig_vec_std_size.so
[paul@login-0-0 stack_swig]$ make
swig -c++ -python a_swig_vec_std_size.i
g++ -fpic -c a_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared a_swig_vec_std_size_wrap.o -o _a_swig_vec_std_size.so
swig -c++ -python b_swig_vec_std_size.i
g++ -fpic -c b_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared b_swig_vec_std_size_wrap.o -o _b_swig_vec_std_size.so
swig -c++ -python c_swig_vec_std_size.i
g++ -fpic -c c_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared c_swig_vec_std_size_wrap.o -o _c_swig_vec_std_size.so
swig -c++ -python -I/public/users/paul/dev/software/swig-3.0.10  d_swig_vec_std_size.i
g++ -fpic -c d_swig_vec_std_size_wrap.cxx -I/public/users/paul/dev/software/Python-2.7.11/Include -I/public/users/paul/dev/software/Python-2.7.11
g++ -g -fpic -shared d_swig_vec_std_size_wrap.o -o _d_swig_vec_std_size.so
[paul@login-0-0 stack_swig]$ python
Python 2.7.11 (default, May  7 2016, 23:37:19) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from d_swig_vec_std_size import StdSizeVec
>>> ssv = StdSizeVec()
>>> vals = ssv.getValues()
>>> vals
<Swig Object of type 'std::vector< std::size_t,std::allocator< std::size_t > > *' at 0x2aba7dd8bd80>
>>> ints - ssv.getInts()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'ints' is not defined
>>> ints = ssv.getInts()
>>> ints
(1, 2)
>>> exit()
swig/python detected a memory leak of type 'std::vector< std::size_t,std::allocator< std::size_t > > *', no destructor found.
[paul@login-0-0 stack_swig]$ cat d_swig_vec_std_size.i 
%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"

namespace std {
  %template(VecSize) vector<size_t>;
}


%include "class_vec_std_size.hpp"

2 ответов


попробуйте определить size_t для swig, как показано здесь -http://www.swig.org/Doc1.3/SWIG.html#SWIG_nn20

%inline %{
typedef long unsigned int size_t;
%}

namespace std {
  %template(VecSize) vector<size_t>;
}

создайте свои шаблоны следующим образом

namespace std {
  %template(VecSize) vector<size_t>;
}

он работает здесь с этим изменением из коробки. Я использую SWIG 3.0.2, g++ 4.9.2 и Python 2.7.9.

Я изменил d_swig_vec_std_size.i в вашем проекте и включить путь к /usr/include/python2.7 в вашем makefile

%module d_swig_vec_std_size
%{
#include "class_vec_std_size.hpp"
%}
%include "std_vector.i"
%template(VecInt) std::vector<int>;

%include "std_size_t.i"

namespace std {
  %template(VecSize) vector<size_t>;
}


%include "class_vec_std_size.hpp"