将元组列表传递到C++函数中

swig pass list of tuples into C++ function

本文关键字:C++ 函数 元组 列表      更新时间:2023-10-16

我正在尝试学习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))。

如果是我在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来处理故障,直到一个工作是我的选择。(值得注意的是,你尝试它们的顺序很重要 - 如果 double 在 int 之前,那么你永远不会选择 int 而不是 double)。

这足以让我运行:

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调用(PyFloat_CheckPyInt_Check等)编写add,但是当我们只能依赖现有的SWIG行为时,这似乎需要付出很多努力来编写更难的代码来维护代码。