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

时间:2014-11-18 16:24:33

标签: python c++ swig

我正在尝试学习SWIG,试图将它与python中的C ++的其他包装器进行比较。我想写的功能之一是这样的:

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

add需要获取元组列表,这些元组的大小为2或3,而不是所有统一类型(因为,你知道,Python)。在SWIG中执行此操作的最简单方法是什么(最终我希望此代码在实际的C ++对象上调用obj.add_int(1, 2)obj.add_double(3, 4.0)

1 个答案:

答案 0 :(得分:1)

如果是我在SWIG中这样做的话,我会尽量写出最少量的奇怪的额外代码。所以我最初的方法是编写一些Python代码来处理异构列表,并找出为列表中的每个条目调用哪个add_TYPE

举个例子:

%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
%}

为了方便演示,我在一个MyObj指令中声明,定义并包装了所有%inline。您可能会略有不同,例如:重载而不是默认参数来区分两个/三个arg版本可能很有意义,并且只能与SWIG一起工作。

add的魔力完全用Python编写,使用了老式的鸭式。作为普通的Python,您可能想要采用的所有常用方法都是开放式的 - 迭代列表并使用try来处理失败,直到我选择了一个工作。 (值得注意的是你在重要事项中尝试它们的顺序 - 如果在int之前加倍,那么你将永远不会选择整数加倍)。

这足以让我跑:

from test import *

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

print('Done')

我用它编译后:

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

结果如预期:

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

您可以通过其他几种方式解决这个问题,最明显的另一种选择是使用大量Python C API调用直接编写addPyFloat_CheckPyInt_Check等。 )但是当我们可以依赖现有的SWIG行为时,这似乎需要付出很多努力来维护代码。