简体   繁体   English

将元组列表传递给C ++函数

[英]swig pass list of tuples into C++ function

I'm trying to learn SWIG, trying to compare it with other wrappers for C++ in python. 我正在尝试学习SWIG,并尝试将其与其他python C ++包装器进行比较。 One of the functions I want to write is something like this: 我要编写的功能之一是这样的:

obj = MyObj()
obj.add([(1,2,), (3,4.0,), (5,"six","string",)])

add needs to take a list of tuples, that are either size 2 or 3 and not all uniform type (because, you know, Python). add需要获取一个元组列表,该元组的大小为2或3,但并非都是统一类型的(因为,Python)。 What is the easiest way to do this in SWIG (ultimately I want this code to call obj.add_int(1, 2) , obj.add_double(3, 4.0) , on the actual C++ object). 在SWIG中执行此操作的最简单方法是什么(最终,我希望此代码在实际C ++对象上调用obj.add_int(1, 2)obj.add_double(3, 4.0) ))。

If it were me doing this in SWIG I'd try to write the least amount of weird extra code possible. 如果是我在SWIG中执行此操作,则尝试编写尽可能少的怪异额外代码。 So my initial approach would be to write some Python code to handle the heterogeneous list and figure out which add_TYPE to call for each entry in the list. 因此,我的最初方法是编写一些Python代码来处理异构列表,并找出要为列表中的每个条目调用哪个add_TYPE

As an example: 举个例子:

%module test

%{
#include <iostream>
#include <limits>
%}

%include <std_string.i>

%inline %{
  struct MyObj {
    void add_double(unsigned a, const double& b, const double& c=std::numeric_limits<double>::quiet_NaN()) {
      std::cout << "add_double(): " << a << ", " << b << ", " << c << "\n";
    }

    void add_int(unsigned a, int b, int c=~0) {
      std::cout << "add_int(): " << a << ", " << b << ", " << c << "\n";
    }

    void add_string(unsigned a, const std::string& b, const std::string& c="") {
      std::cout << "add_string(): " << a << ", " << b << ", " << c << "\n";
    }
  };
%}

%pythoncode %{
def obj_add(self, items):
  tries = (self.add_int, self.add_double, self.add_string)

  for args in items:
    for method in tries:
      good = False
      try:
        method(*args)
      except NotImplementedError:
        pass # Just pick a different version
      else:
        good = True
        break

    if not good: raise TypeError('No matches')

MyObj.add = obj_add
%}

For convenience of a demo I declared, defined and wrapped all of MyObj in the one %inline directive. 为了方便演示,我在一个%inline指令中声明,定义和包装了所有MyObj You might have slight variations on this, eg overloads instead of default arguments to distinguish the two/three arg versions probably makes a lot of sense and would 'just work' with SWIG also. 您可能对此略有不同,例如,重载代替默认参数以区分两个/三个arg版本可能很有意义,并且也可以与SWIG一起使用。

The magic of add is written entirely in Python using good old fashioned ducktyping. add的神奇之处完全是使用良好的老式鸭子打字方式在Python中编写的。 Being plain Python all the usual approaches to this that you might want to take are open - iterating over the list and using try to handle failures until one works was my choice. 作为普通Python,您可能要采取的所有常规方法都是开放的-在列表中进行迭代并try处理失败,直到我选择了一种方法为止。 (Worth noting that the order you try them in matters - if double comes before int then you'll never pick int over double). (值得一提的是,您尝试使用它们的顺序很重要-如果double在int之前出现,那么您将永远不会选择int超过double)。

This was sufficient to let me run: 这足以让我运行:

from test import *

obj = MyObj()
obj.add([(1,2,), (3,4.0,), (5,"six","string",)])

print('Done')

Once I had compiled it with: 一旦我用它编译:

swig -py3 -c++ -python -Wall test.i
g++ -Wall -Wextra test_wrap.cxx -I/usr/include/python3.4/ -lpython3.4m -shared -o _test.so

And the result was as expected: 结果与预期的一样:

add_int(): 1, 2, -1
add_double(): 3, 4, nan
add_string(): 5, six, string
Done

You could have solved this in quite a few other ways, the most obvious other choice being to write add directly using lots of Python C API calls ( PyFloat_Check , PyInt_Check etc.) but that seems like a lot of effort to write harder to maintain code when we could just rely on existing SWIG behaviour. 您可能还可以通过其他多种方式解决此问题,最明显的其他选择是直接使用大量Python C API调用( PyFloat_CheckPyInt_Check等)编写add ,但这似乎要花费很多精力来编写更难维护的代码当我们可以仅仅依靠现有的SWIG行为时。

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

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