【问题标题】:How to access C++ typedef'd structures in python with SWIG interface如何使用 SWIG 接口在 python 中访问 C++ typedef'd 结构
【发布时间】:2019-10-30 19:17:25
【问题描述】:

我正在尝试配置我的 SWIG 接口以公开所有已定义的 typedef。

示例:对于我的 C++ 头文件中的以下内容,我希望我的 python 代码能够创建对象 A、B、C、D、E。

//MyHeader.h
struct Common
{
    uint8_t     eId;
};
typedef Common A, B, C, D, E;

我在头文件中使用以下结构进行了测试,通过 SWIG 接口可用的对象是 Test、Test2Typedef 和 Test3Typedef1,但不是 TestTypedef、Test2、Test3 或 Test3Typedef2。

//MyHeader.h
struct Test {
    uint8_t uValue;
};
typedef Test TestTypedef;

typedef struct Test2 {
    uint8_t uValue;
} Test2Typedef;

typedef struct Test3 {
    uint8_t uValue;
} Test3Typedef1, Test3Typedef2;

我已尝试将以下 typedef 添加到我的 .i 文件中,但仍然无法访问 TestTypedef:

//MyHeader.i
%{
#include "MyHeader.h"
typedef Test TestTypedef;
%}

typedef Test TestTypedef;
%include "MyHeader.h"

【问题讨论】:

    标签: python c++ swig


    【解决方案1】:

    作为一般规则,SWIG 尝试在目标语言中尽可能地反映 C 的行为。有时这有点棘手,尽管没有将 typedef 语义映射到许多 SWIG 目标语言的一般情况下。在这个特定的例子中,尽管您仍然可以使用两种可能的选项之一来实现您在 Python 中寻找的行为。为了简化事情,尽管您希望在标题中更加一致,所以要么总是 typedef TestN 结构,要么永远不要 typedef 它们。

    首先,您可以在%pythoncode 中编写一些额外的 Python 代码,以确保 Python 中的每种类型都有一个与您期望的匹配的别名。如下界面显示:

    %module test
    
    
    %inline %{
    
    struct Test {
        uint8_t uValue;
    };
    typedef Test TestTypedef;
    
    struct Test2 {
        uint8_t uValue;
    };
    typedef Test2 Test2Typedef;
    
    struct Test3 {
        uint8_t uValue;
    };
     typedef Test3 Test3Typedef1, Test3Typedef2;
    
    %}
    
    %pythoncode %{
      TestTypedef = Test
      Test2Typedef = Test2
      Test3Typedef1 = Test3
      Test3Typedef2 = Test3
    %}
    

    然而,另一种方法是在 C++ 层内做一些诡计。实际上,我们所要做的就是确保 SWIG 生成我们想要的接口,并且它都是合法、正确、可编译的 C++ 代码。然而,如果我们在 C++ 代码的真实情况上对 SWIG 撒谎并不重要。所以在实践中,如果我们声称我们的每个 typedef 实际上是一个派生类,但实际上它们只是 typedef,那么我们最终仍然会得到一个完美工作的接口。作为奖励,目标语言中的大部分内容将更加类型安全,这可能是好的:

    %module test
    
    
    %{
    // This is what the C++ compiler sees:    
    struct Test {
        uint8_t uValue;
    };
    typedef Test TestTypedef;
    
    struct Test2 {
        uint8_t uValue;
    };
    typedef Test2 Test2Typedef;
    
    struct Test3 {
        uint8_t uValue;
    };
    typedef Test3 Test3Typedef1, Test3Typedef2;
    
    %}
    
    // This is the lie we tell SWIG, but it's compatible with what the C++ code really is doing
    struct Test {
        uint8_t uValue;
    };
    
    struct Test2 {
        uint8_t uValue;
    };
    
    struct Test3 {
        uint8_t uValue;
    };
    
    struct Test2Typedef : Test2 {};
    struct Test3Typedef1 : Test3 {};
    struct Test3Typedef2 : Test3 {};
    

    其中任何一个都可以让我们运行这个 Python 代码:

    import test
    
    a = test.Test3Typedef2()
    

    如果是我这样做,我会为 typedef 生成定义一个宏:

    #ifndef SWIG
    #define MAKE_TYPEDEF(original, renamed) typedef original renamed
    #else
    #define MAKE_TYPEDEF(original, renamed) struct renamed : original {}
    #endif 
    

    然后它可以存在于头文件中,并且允许您仍然使用%include

    【讨论】:

    • @paige 值得指出的是,我怀疑您正在尝试实现的目标可能比这些选项中的任何一个都适合更简洁的 Python/C++ 绑定生成解决方案,但很难说确定没有更多细节
    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-05
    • 1970-01-01
    • 2011-09-04
    • 2022-09-22
    相关资源
    最近更新 更多