简体   繁体   English

SWIG 将向量向量转换为 Python 的列表列表,此 scope 中未声明“x”

[英]SWIG Converting a vector of vectors to a list of lists for Python, 'x' was not declared in this scope

I have a short c++ function that populates a vector of vectors when given inputs a,b which are rows and columns, like this vec_of_vec.cpp我有一个简短的 c++ function 当给定输入 a,b 是行和列时填充一个向量向量,就像这个 vec_of_vec.cpp

#include <iostream>
#include "vec_of_vec.h"
#include <vector>

std::vector<std::vector<int>> f(int a, int b) {
    std::vector<std::vector<int>> mat;

    for (int i = 0; i < a; i++)
    {
        // construct a vector of int
        std::vector<int> v;
        for (int j = 0; j < b; j++) {
            v.push_back(j+i);
        }

        // push back above one-dimensional vector
        mat.push_back(v);
    }
return mat;
}

its header file vec_of_vec.h它的 header 文件 vec_of_vec.h

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED

#include <vector>
#include <functional>
std::vector<std::vector<int>> f(int a,int b); 

#endif

From here I want to call this code from python so I try and wrap it with SWIG.从这里我想从 python 调用这段代码,所以我尝试用 SWIG 包装它。 This is the interface file I've been using.这是我一直在使用的接口文件。 I've taken inspiration from this post.我从这篇文章中获得了灵感。

vec_of_vec.i vec_of_vec.i

%module vec_of_vec
#define SWIGPYTHON_BUILTIN
%{
#include "vec_of_vec.h"
#include <vector>
%}

%include <std_vector.i>
%template(VectorOfInt) std::vector<int>;
%template(VectorOfStructVector) std::vector<std::vector<int> >;


%typemap(out) std::vector<std::vector<int>> (PyObject* _inner,PyObject* _outer) %{
    // Allocate a PyList object of the requested size.
    _outer = PyList_New($1.size());
    // Populate the PyList.  PyLong_FromLong converts a C++ "long" to a
    // Python PyLong object.
    for(int x = 0; x < $1.size(); x++)
        _inner = PyList_New($1[x].size());
        for(int y = 0; y < $1[x].size(); y++)
            PyList_SetItem(_inner,y,PyLong_FromLong($1[x][y]));
        PyList_SetItem(_outer,x,_inner);
   $result = SWIG_Python_AppendOutput($result,_outer);
%}

%include "vec_of_vec.h"

This is the makefile:这是 makefile:

all:
        rm -f *.so *.o *_wrap.* *.pyc *.gch vec_of_vec.py
        swig -c++ -python vec_of_vec.i
        g++ -fpic -c vec_of_vec_wrap.cxx vec_of_vec.h vec_of_vec.cpp -I/usr/include/python3.8
        g++ -shared vec_of_vec_wrap.o vec_of_vec.o -o _vec_of_vec.so

When I call this I get an error:当我调用它时,我得到一个错误:

vec_of_vec_wrap.cxx: In function ‘PyObject* _wrap_f(PyObject*, PyObject*)’:
vec_of_vec_wrap.cxx:9412:3: error: expected initializer before ‘for’
 9412 |   for(x = 0; x < (&result)->size(); x++)
      |   ^~~
vec_of_vec_wrap.cxx:9412:40: error: expected ‘;’ before ‘)’ token
 9412 |   for(x = 0; x < (&result)->size(); x++)
      |                                        ^
      |                                        ;
vec_of_vec_wrap.cxx:9414:7: error: ‘y’ was not declared in this scope
 9414 |   for(y = 0; y < result[x].size(); y++)
      |       ^
make: *** [makefile:4: all] Error 1

However when I try and populate it manually, in the interface file, without a for loop, something similar to this:但是,当我尝试在接口文件中手动填充它时,没有 for 循环,类似于以下内容:

%typemap(out) std::vector<std::vector<int>> (PyObject* _inner,PyObject* _outer) %{
    // Allocate a PyList object of the requested size.
    _outer = PyList_New($1.size());
    _inner = PyList_New($1[0].size());
    PyList_SetItem(_inner,0,PyLong_FromLong($1[0][0]));
    PyList_SetItem(_inner,1,PyLong_FromLong($1[0][1]));
    PyList_SetItem(_outer,0,_inner);
    ...
    $result = SWIG_Python_AppendOutput($result,_outer);
%}

it returns a list of lists.它返回一个列表列表。

Another thing is that if i change %typemap(out) to %typemap(argout), I get a tuple of tuples back, but it works without errors.另一件事是,如果我将 %typemap(out) 更改为 %typemap(argout),我会得到一个元组的元组,但它可以正常工作。

If it's not obvious, I'm not very proficient with c++ or swig but I'm trying to find my way around it but can't figure it out for the life of me.如果不是很明显,我对 c++ 或 swig 不是很精通,但我正试图找到解决方法,但终生无法弄清楚。

You were close, although the error message doesn't agree with the code shown or the error in the title.尽管错误消息与显示的代码或标题中的错误不符,但您已经接近了。 Code shown is for(int x = 0...) but error message is for(x = 0...) .显示的代码是for(int x = 0...)但错误消息是for(x = 0...) In the code shown you are missing the marked curly braces below in the %typemap(out) implementation:在显示的代码中,您在%typemap(out)实现中缺少下面标记的花括号:

%typemap(out) std::vector<std::vector<int>> (PyObject* _inner,PyObject* _outer) %{
    // Allocate a PyList object of the requested size.
    _outer = PyList_New($1.size());
    // Populate the PyList.  PyLong_FromLong converts a C++ "long" to a
    // Python PyLong object.
    for(int x = 0; x < $1.size(); x++) {  // <<<<<<< MISSING
        _inner = PyList_New($1[x].size());
        for(int y = 0; y < $1[x].size(); y++)
            PyList_SetItem(_inner,y,PyLong_FromLong($1[x][y]));
        PyList_SetItem(_outer,x,_inner);
    } // <<<<<<< MISSING
   $result = SWIG_Python_AppendOutput($result,_outer);
%}

Output after fix: Output 修复后:

>>> import vec_of_vec as vv
>>> vv.f(3,5)
[[0, 1, 2, 3, 4], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6]]

Note that your code worked with %typemap(argout) because there is a default %typemap(out) for the vector<vector<int>> template you declared that generates a tuple of tuples, and %typemap(argout) simply wasn't used.请注意,您的代码与%typemap(argout)一起使用,因为您声明的vector<vector<int>>模板有一个默认的%typemap(out)生成元组的元组,而%typemap(argout)根本不是用过的。 If a tuple of tuples is OK for you, then you don't need the %typemap(out) that outputs a list of lists.如果元组的元组对您来说可以,那么您不需要输出列表列表的%typemap(out)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM