如何为类类型创建 OUTPUT 类型映射?

Posted

技术标签:

【中文标题】如何为类类型创建 OUTPUT 类型映射?【英文标题】:How to create an OUTPUT typemap for a class type? 【发布时间】:2015-10-29 12:03:09 【问题描述】:

我之前在尝试将 SWIG 的 OUTPUT 类型映射应用于类类型时遇到了麻烦,并问了这个previous question。

我得到的答案很有帮助,但仍然需要我要求 SWIG 执行以下操作:

%apply exportedClassType& OUTPUT  exportedClassType& result ;

这在 SWIG 3.0.6 上似乎对我不起作用,并显示以下消息:

Warning 453: Can't apply (exportedClassType &OUTPUT). No typemaps are defined.

从the documentation看:

请注意,typemaps.i 文件的主要目的是支持原始数据类型。写一个这样的函数 void foo(Bar *OUTPUT); 可能没有预期的效果,因为 typemaps.i 没有为 Bar 定义 OUTPUT 规则。

这似乎不受支持。所以我想我的问题是,我需要在 interface.i 文件中定义什么类型映射组合,以便为类类型生成的包装器代码从此开始:

// interface.i
%apply exportedClassType& OUTPUT  exportedClassType& result ;
int getClassType(exportedClassType& result);

// interface_wrap.cxx
SWIGINTERN PyObject *_wrap_getClassType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) 
  PyObject *resultobj = 0;
  exportedClassType *arg1 = 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  PyObject * obj0 = 0 ;
  int result;

  if (!PyArg_ParseTuple(args,(char *)"O:getClassType",&obj0)) SWIG_fail;
  res1 = SWIG_ConvertPtr(obj0, &argp1, SWIGTYPE_p_exportedClassType,  0 );
  if (!SWIG_IsOK(res1)) 
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "getClassType" "', argument " "1"" of type '" "exportedClassType &""'"); 
  
  if (!argp1) 
    SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "getClassType" "', argument " "1"" of type '" "exportedClassType &""'"); 
  
  arg1 = reinterpret_cast< exportedClassType * >(argp1);
  result = (int)getClassType(*arg1);
  resultobj = SWIG_From_int(static_cast< int >(result));
  return resultobj;
fail:
  return NULL;


// wrapper.py
def getClassType(result):
    return _wrapper.getClassType(result)
getClassType = _wrapper.getClassType

更喜欢这样的东西?

// interface.i
%apply bool& OUTPUT  bool& result ;
int getSimpleType(bool& result); 

// interface_wrap.cxx
SWIGINTERN PyObject *_wrap_getSimpleType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) 
  PyObject *resultobj = 0;
  bool *arg1 = 0 ;
  bool temp1 ;
  int res1 = SWIG_TMPOBJ ;
  int result;

  arg1 = &temp1;
  if (!PyArg_ParseTuple(args,(char *)":getSimpleType")) SWIG_fail;
  result = (int)getSimpleType(*arg1);
  resultobj = SWIG_From_int(static_cast< int >(result));
  if (SWIG_IsTmpObj(res1)) 
    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_bool((*arg1)));
   else 
    int new_flags = SWIG_IsNewObj(res1) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg1), SWIGTYPE_p_bool, new_flags));
  
  return resultobj;
fail:
  return NULL;


// wrapper.py
def getSimpleType():
    return _wrapper.getSimpleType()
getSimpleType = _wrapper.getSimpleType

我不知道需要什么 in/out/argout 类型映射,以便为我的 exportedClassType 调用 SWIG_Python_AppendOutput 等。有人可以给我一些指示吗?没有双关语。

【问题讨论】:

您能否提供您要导出的方法的原型。我通常包装构造函数并让 SWIG 处理多态性,但设法创建了一个工厂,其中输出是通过引用。 How to apply SWIG OUTPUT typemaps for class types in Python?的可能重复 【参考方案1】:

可以使用inargout 类型映射的组合来实现所需的行为。我把它放在一个宏 class_output_typemaps 中,这样就可以使用以下语法启用它

%class_output_typemaps(exportedClassType)
%apply (exportedClassType*& ARGOUT_OBJECT) (exportedClassType *&result)

下面给出一个完整的例子

example.h

#pragma once
class exportedClassType 
 public:
  exportedClassType();
  ~exportedClassType();
;
int getClassType(exportedClassType*& result);

example.cpp

#include "example.h"
#include <cstdio>

int getClassType(exportedClassType*& result) 
  result = new exportedClassType();
  return 0;


exportedClassType::exportedClassType() printf("ctor\n");
exportedClassType::~exportedClassType() printf("dtor\n");

example.i

%module example
%
  #define SWIG_FILE_WITH_INIT
  #include "example.h"
%

%include "typemaps.i"

/* %class_output_typemaps() macro
 *
 * It must be executed for each class CLASS_TYPE, which needs typemaps for output
 */
%define %class_output_typemaps(CLASS_TYPE)

%typemap(in, numinputs=0) (CLASS_TYPE *&ARGOUT_OBJECT) (CLASS_TYPE* temp) 
  $1 = &temp;


%typemap(argout) (CLASS_TYPE *&ARGOUT_OBJECT) 
  CLASS_TYPE* newObj;
  *(CLASS_TYPE**)&newObj = *$1;

  PyObject* temp = NULL;
  if (!PyList_Check($result)) 
    temp = $result;
    $result = PyList_New(1);
    PyList_SetItem($result, 0, temp);
  

  temp = SWIG_NewPointerObj(SWIG_as_voidptr(newObj),
                $descriptor(CLASS_TYPE*),
                SWIG_POINTER_OWN | 0);

  PyList_Append($result, temp);
  Py_DECREF(temp);


%enddef    /* %class_output_typemaps() */

%class_output_typemaps(exportedClassType)

%apply (exportedClassType*& ARGOUT_OBJECT) (exportedClassType *&result)

%include "example.h"

setup.py

#!/usr/bin/env python
from distutils.core import setup, Extension
import numpy
import os

setup(name='test',
      version='1.0',
      ext_modules =[Extension('_example',
                              ['example.i', 'example.cpp'],
                              swig_opts=['-c++'],
                              include_dirs = ['.'])])

使用 python setup.py build_ext --inplace 构建后,您可以使用 Python 在 Python 中创建对象

import example
myExportedClassType = example.getClassType()[1]

【讨论】:

以上是关于如何为类类型创建 OUTPUT 类型映射?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Spring Security 创建类型安全的用户角色?

如何为具有多种父类型的子场景编写 EF 代码优先映射

如何为数据框中的复杂列创建包含数组(案例类)的udf

如何为视觉框架创建 MLFeatureProvider 类

如何为自定义类的参数指定类型提示? [复制]

如何为记录类型创建布尔类型的字段?