SWIG C++/Python绑定和支持具有std::enable_i条件成员

2024-04-25 03:45:55 发布

您现在位置:Python中文网/ 问答频道 /正文

对不起,对于长标题,这里是我要实现的:我有一个小的C++类,它带有一个布尔模板参数,当它是真的时,使用^ {CD1>}禁用它的SETTER方法。下面是一个简化的示例:

template< bool IS_CONST >
class Handle
{
public:

    Handle(void) : m_value(0) { }
    Handle(int value) : m_value(value) { }

    template < bool T = IS_CONST, typename COMPILED = typename std::enable_if< T == false >::type >
    void set(int value)
    {
        m_value = value;
    }

    int get(void) const
    {
        return m_value;
    }

private:
    int m_value;
};

这段代码按预期编译了一个作品:Handle< true >没有set方法,Handle< false >有它。你知道吗

现在我正在尝试使用SWIG将其绑定到Python。我正在使用以下文件生成绑定:

%module core

%include "Handle.h"

%template(NonConstHandle) Handle< false >;
%template(ConstHandle) Handle< false >;

%{
#include "Test.h"
%}

SWIG毫无怨言地生成模块,它编译得很好,但是set方法从不绑定,即使在专门的NonConstHandle中也是如此。e、 g.以下Python测试因AttributeError: 'NonConstHandle' object has no attribute 'set'而失败:

import core

handle = core.NonConstHandle()
assert(handle.get() == 0)
handle.set(1)
assert(handle.get() == 1)

const_handle = core.ConstHandle()
assert(const_handle .get() == 0)
try:
    const_handle .set(1)
    print("this should not print")
except:
    pass

print("all good")

当我搜索这个主题时,我发现了很多与enable\u if和SWIG相关的东西,这让我觉得它是受支持的,但是我不明白为什么没有生成set,尽管SWIG没有发出错误/警告。。。你知道吗

感谢您的帮助! 敬礼


Tags: 方法corefalsegetvaluetemplateassertswig
1条回答
网友
1楼 · 发布于 2024-04-25 03:45:55

问题在于,每次在C++中创建模板时,在SWIG接口中至少需要一个^ {{CD1>}指令,以便对生成的包装器有任何影响。你知道吗

当人们含糊地暗示std::enable_if有效时,他们通常意味着两件事。首先它解析的是ok,其次是%template对它们有效。这两件事在这里都是真的。你知道吗

由于在模板类中使用了SFINAE和模板函数,因此每个函数都需要一个%template。否则set成员将被完全忽略,如您所见。如果你的问题有一点是一个好的开始,那么跳过SFINAE/enable\u是一个好的开始。你知道吗

我们可以把你的.i文件改成这样:

%module test 

%{
#include "test.h"
%}

%include "test.h"

// Be explicit about what 'versions' of set to instantiate in our wrapper    
%template(set) Handle::set<false, void>;

%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;

问题是(修复了其中的一些小错误)您的测试python现在遇到了“this should not print”,因为我们已经生成了一个(完全合法的)set()函数,即使在const情况下也是通过显式地拼写模板参数,而不是推导它们。你知道吗

所以我们生成了要调用的代码:

Handle<true>::set<false, void>(int);

它在这个例子中是有效的,因为它不能以直观的方式编译。你知道吗

我不知道有什么方法可以在这里进行扣减(这很遗憾,因为它们是默认的,所以应该可以对吗?-也许有一个是为了给SWIG trunk打补丁,尽管做default和SFINAE都会很棘手)

幸运的是,有一个简单的解决方法,使用%ignore删除我们不想要的版本:

%模块测试

%{
#include "test.h"
%}

%include "test.h"

%template(set) Handle::set<false, void>;
%ignore Handle<true>::set;

%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;

它会生成您期望的代码。你知道吗


值得注意的是,在生成包装器时,通常更容易显式地说明您希望复杂模板化代码的工作方式—您通常需要对接口进行额外的帮助或调整,以使其以您希望的方式在Python中工作。所以你也可以通过这样做来解决你的例子:

%module test

%{
#include "test.h"
%}

template <bool>
class Handle {
public:
    Handle(void);
    Handle(int value);

    int get(void) const;
};

template<>
class Handle<false>
{
public:
    Handle(void);
    Handle(int value);

    void set(int value);
    int get(void) const;
};

%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;

或者类似的伎俩:

%module test 

%{
#include "test.h"
typedef Handle<true> ConstHandle;
typedef Handle<false> NonConstHandle;
%}

struct ConstHandle {
    ConstHandle(void);
    ConstHandle(int value);

    int get(void) const; 
};

struct NonConstHandle
{
    NonConstHandle(void);
    NonConstHandle(int value);

    void set(int value);
    int get(void) const;
};

但是请注意,在最后一种情况下,如果要将模板用作函数中的参数或函数外的参数,则还需要使用%apply。你知道吗

相关问题 更多 >