如何使用 SIP 将 std::list 从 C++ 翻译成 python

How to translate std::list from c++ to python with SIP

我正在使用带有 python 3.8 的 SIP 版本 6.0.1 并且有给定的 c++11 API。 (在 Ubuntu 18.04)

目标是存储例如使用 python.

在 std::list 中自定义结构指针(我也用 sip 翻译的结构)

我构建了一个小例子来说明我的情况:

std_list.sip 文件

%Module(name=std_list, language="C++")

%Include type_list.sip

%DefaultEncoding "UTF-8"

struct TestStruct {

%TypeHeaderCode
#include <std_list.h>
%End

    int test1;
    int test2;

    void printStruct() const;
    TestStruct();
};

typedef std::list<TestStruct*> ListTestStruct;

struct StructContainerLvl2 {

%TypeHeaderCode
#include <std_list.h>
%End

    ListTestStruct listTestStruct;
    StructContainerLvl2();
};

type_list.sip 列表翻译文件

template<TYPE *>
%MappedType std::list<TYPE *> /TypeHint="List[TYPE]"/ {
%TypeHeaderCode
#include <list>
%End

%ConvertFromTypeCode
    PyObject *l;

    const sipTypeDef* kpTypeDef = sipFindType("TYPE");

    if (!kpTypeDef) {
        return NULL;
    }

    // Create the Python list of the correct length.
    if ((l = PyList_New(sipCpp->size())) == NULL) {
        return NULL;
    }

    int i = 0;
    for(std::list<TYPE *>::iterator iter = sipCpp->begin(); iter != sipCpp->end(); iter++) {
        TYPE *cpp = *iter;
        PyObject *pobj;

        // Get the Python wrapper for the Type instance, creating a new
        // one if necessary, and handle any ownership transfer.
        if ((pobj = sipConvertFromType(cpp, kpTypeDef, sipTransferObj)) == NULL) {
            // There was an error so garbage collect the Python list.
            Py_XDECREF(l);
            return NULL;
        }

        // Add the wrapper to the list.
        PyList_SET_ITEM(l, i++, pobj);
    }

    // Return the Python list.
    return l;
%End

%ConvertToTypeCode
    const sipTypeDef* kpTypeDef = sipFindType("TYPE");

    if (!kpTypeDef) {
        return 0;
    }

    // Check if type is compatible
    if (sipIsErr == NULL) {
        if (!PyList_Check(sipPy)) {
            return 0;
        }
        for (Py_ssize_t i = 0; i < PyList_GET_SIZE(sipPy); ++i) {
            PyObject *item = PyList_GET_ITEM(sipPy, i);
            if (!sipCanConvertToType(item, kpTypeDef, SIP_NOT_NONE)) {
                return 0;
            }
        }
        return 1;
    }
    // Convert Python list of TYPE to std::list<TYPE*>
    std::list<TYPE*> *l = new std::list<TYPE*>();

    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(sipPy); ++i) {
        int state;
        PyObject *item = PyList_GET_ITEM(sipPy, i);
        TYPE* p = static_cast<TYPE*>(sipConvertToType(item, kpTypeDef, NULL, SIP_NOT_NONE, &state, sipIsErr));

        if (*sipIsErr) {
            sipReleaseType(p, kpTypeDef, state);
            delete l;
            return 0;
        }

        sipTransferTo(item, item);
        l->push_back(p);

        sipReleaseType(p, kpTypeDef, state);
    }

    *sipCppPtr = l;
    return sipGetState(sipTransferObj);
%End
};

std_list.h 文件

#include <list>

struct TestStruct {

    int test1{};
    int test2{};

    void printStruct() const;
    TestStruct() = default;
};

typedef std::list<TestStruct*> ListTestStruct;

struct StructContainerLvl2 {
    ListTestStruct listTestStruct;
    StructContainerLvl2() = default;
};

test.py 文件

import std_list

if __name__ == '__main__':

    testStruct1 = std_list.TestStruct()
    testStruct1.test1 = 1
    testStruct1.test2 = 2

    testStruct2 = std_list.TestStruct()
    testStruct2.test1 = 21
    testStruct2.test2 = 22

    temp_structContainerLvl2 = std_list.StructContainerLvl2()

    print(temp_structContainerLvl2.listTestStruct)

    temp_structContainerLvl2.listTestStruct.append(testStruct1)
    temp_structContainerLvl2.listTestStruct.append(testStruct2)

    print(temp_structContainerLvl2.listTestStruct)

    for item in temp_structContainerLvl2.listTestStruct:
        print("List item {}".format(item))
        print()

问题是列表总是空的。无论我尝试在其中存储什么。 错误可能在 type_list.sip 文件中。我更新了一个我找到的例子,但我不确定它是否正确。

有人可以帮忙吗?

谢谢强尼

问题不在 type_list.sip 文件中,而是在 test.py 文件中。

将某些内容附加到已翻译的 python 列表中的 cmd,其附加方式类似于 ...

temp_structContainerLvl2.listTestStruct.append(testStruct1)

不能用于 python 列表的 sip 翻译。

作为一种解决方法,可以使用

temp_structContainerLvl2.listTestStruct = [testStruct1, testStruct2]

temp_structContainerLvl2.listTestStruct += [testStruct3]

我想它不是那么有效,但我现在已经有了。