How can I collapse multiple arguments into one SWIG parameter

浪尽此生 提交于 2019-12-23 03:45:26

问题


I'm trying to write a typemap that converts multiple/variable arguments into one input parameter.

For example, say I have a function that takes a vector.

void foo(vector<int> x);

And I want to call it like this (happens to be in Perl)

foo(1,2,3,4);

The typemap should take arguments ($argnum, ...), gather them into one vector and then pass that to foo.

I have this so far:

typedef vector<int> vectori;
%typemap(in) (vectori) {
  for (int i=$argnum-1; i<items; i++) {
      $1->push_back( <argv i> );   // This is language dependent, of course.
  }
}

This would work, except that SWIG checks the number of arguments

if ((items < 1) || (items > 1)) {
  SWIG_croak("Usage: foo(vectori);");
}

If I do:

 void foo(vectori, ...);

SWIG will expect to call foo with two arguments.

 foo(arg1, arg2);

Perhaps there's a way to tell SWIG to suppress arg2 from the call to foo?

I can't use this in my .i:

void foo(...)

because I want to have different typemaps, depending on the types that foo is expecting (an array of int, strings, whatever). Maybe there's a way to give a type to "..."

Is there a way to do this?


回答1:


SWIG has built-in support for some STL classes. Try this for your SWIG .i file:

%module mymod

%{
#include <vector>
#include <string>
void foo_int(std::vector<int> i);
void foo_str(std::vector<std::string> i);
%}

%include <std_vector.i>
%include <std_string.i>
// Declare each template used so SWIG exports an interface.
%template(vector_int) std::vector<int>;
%template(vector_str) std::vector<std::string>;

void foo_int(std::vector<int> i);
void foo_str(std::vector<std::string> i);

Then call it with array syntax in the language of choice:

#Python
import mymod
mymod.foo_int([1,2,3,4])
mymod.foo_str(['abc','def','ghi'])



回答2:


SWIG determines the argument count at the time SWIG generates the bindings. SWIG does provide some limited support for variable argument lists but I'm not sure this is the right approach to take. If you're interested, you can read more about it in the SWIG vararg documentation section.

I think a better approach would be to pass these values in as an array reference. Your typemap would then look something like this (not tested):

%typemap(in) vectori (vector<int> tmp)
{
    if (!SvROK($input))
        croak("Argument $argnum is not a reference.");

    if (SvTYPE(SvRV($input)) != SVt_PVAV) 
        croak("Argument $argnum is not an array.");

    $1 = &$tmp;

    AV *arrayValue = (AV*)SvRV($input);
    int arrayLen = av_len(arrayLen);

    for (int i=0; i<=arrayLen; ++i) 
    {
        SV* scalarValue = av_fetch(arrayValue , i, 0);
        $1->push_back( SvPV(*scalarValue, PL_na) );
    }
};

Then from Perl you'd use array notation:

@myarray = (1, 2, 3, 4);
foo(\@myarray);


来源:https://stackoverflow.com/questions/1247536/how-can-i-collapse-multiple-arguments-into-one-swig-parameter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!