gpt4 book ai didi

python - SWIG C++/Python 绑定(bind)和支持带有 std::enable_if 的条件成员

转载 作者:行者123 更新时间:2023-11-30 03:17:34 25 4
gpt4 key购买 nike

抱歉,标题太长了,这就是我想要实现的目标:我有一个带有 bool 模板参数的小型 C++ 类,当它为真时,使用 std::enable_if 禁用它的 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 将它绑定(bind)到 Python。我正在使用以下文件生成绑定(bind):

%module core

%include "Handle.h"

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

%{
#include "Test.h"
%}

SWIG 毫无怨言地生成了模块,它编译得很好,但是 set方法永远不会绑定(bind),即使在专门的 NonConstHandle 中也是如此.例如以下 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_if 和 SWIG 相关的东西,这让我认为它是受支持的,但我不明白为什么 set不会生成,尽管 SWIG 没有发出错误/警告...

感谢任何帮助!问候

最佳答案

这里的问题是,每次您在 C++ 中创建模板时,您的 SWIG 接口(interface)中至少需要一个 %template 指令,以便它对生成的包装器产生任何影响。

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

由于您在模板类中使用了 SFINAE 和模板函数,因此您需要为每个模板函数创建一个 %template。否则,如您所见,set 成员将被完全忽略。避开问题的 SFINAE/enable_if 位 example of template functions inside template classes是一个很好的起点。

所以我们可以将您的 .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 现在点击“这不应该打印”,因为我们已经生成了一个(完全合法的)set() 函数即使在 const 情况下,通过明确拼出模板参数而不是推导它们。

所以我们已经生成代码来调用:

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

在这种情况下,嗯,因为它可以编译而不是以直观的方式。

我不知道在这里进行扣除的方法(这很遗憾,因为它们是默认的,所以它应该是可能的吧?-也许是 SWIG 的补丁trunk,尽管同时进行默认设置和 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>;

然后它会生成您期望的代码。


值得注意的是,在生成包装器时明确说明您希望复杂模板代码的工作方式通常更简单 - 您通常需要额外的帮助程序或对接口(interface)进行调整以使其以您希望的方式在 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

关于python - SWIG C++/Python 绑定(bind)和支持带有 std::enable_if 的条件成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55363662/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com