2016-11-15 96 views
0

创建typedefd类型的变量我有痛饮项目设置生成Python代码。我有一个std::stringtypedefMessage一个say(Message)功能。我可以用python中的字符串调用say。我希望能够创建类型为Message的变量,并且Message类型被导出到库中,但不是python包装器。下面是我的文件:在痛饮

test.h

#include <string> 
#include <iostream> 

typedef std::string Message 
void say(Message s); 

TEST.CPP

#include "test.h" 

void say(Message s) 
{ 
    std::cout << s << std::endl; 
} 

test.i

%module test 
%{ 
#include "test.h" 
%} 

typedef std::string Message; 
%include "std_string.i" 
%include "test.h" 

Python的例子

import test 
test.say('a') 
# >>> a 

# What I want to be able to do 
msg = test.Message('a') 
# >>> Traceback (most recent call last): 
# >>> File "<stdin>", line 1, in <module> 
# >>> AttributeError: module 'test' has no attribute 'Message' 

我的实际使用案例还涉及对其他类型(主要是枚举)的typedefs,如果这些案例采取了不同的处理方式,我很好奇。我相信我可以将对象包装在SWIG绑定的类中,然后修改SWIG生成的类(或者可以使用SWIG类型映射),但是我觉得这是一个迂回解决方案,我认为这是一种常见的情况。

我认为这可能是访问string标题中的代码的问题,但如果我尝试敲入类似int之类的东西,我会遇到同样的问题。

我的最好的方法,到目前为止已被包装的模板:

template<typename T> 
class Wrapper 
{ 
public: 
    Wrapper(T x) : data(x){}; 
    T data; 
    T operator()() { return data; }; 
}; 

而且相应的%template指令在test.i

%template(Message) Wrapper<std::string>; 

不幸的是,这似乎有几个缺点至今:

  • 你必须实际LY打电话operator(),即需要test.Message('a')()被称为
  • 您需要可以选用一些条件编译或名称,包装的东西从不同的typedef;否则,test.say将不接受包装或字符串,因此根本无法使用。
  • 它似乎并不与施工错误枚举工作。

我也认为我可能很聪明,并改变operator*只是返回正在包装,但它看起来像SWIG包裹什么是返回无论如何。

+0

我建议你使用'const char *',因为'std :: string'不是'POC'类型,并且内存分配在堆上,不管它是调试版本还是发行版本,其操作都是不同的。我预计通过包含'%include“std_string.i”'你可以创建一个'std :: string'实例。你有没有尝试过使用这个参数? –

+0

我的预期是错误的,但我仍然建议您在界面上使用POC类型。 –

+0

我希望能够将'%include std_string.i'或%import std_string.i'中的字符串实例化为'std_string.i'模板'string'作为'basic_string '。奇怪的是,这些似乎都没有导入一个可以创建实例的对象。也许这是因为SWIG似乎通过将字符串映射到目标语言字符串来处理字符串? – danielunderwood

回答

0

一般在痛饮类型定义应该“只是工作”。 (有一个例外,我知道他们经常不按预期行为和实例化模板时的,但在这里,这不是一个问题。)

在您的例子我觉得你的问题很简单typedef的知名度相对于std::string的定义。如果你改变你的。我的文件是:

%module test 
%{ 
#include "test.h" 
%} 

%include "std_string.i" 
typedef std::string Message; 
%include "test.h" 

还是

%module test 
%{ 
#include "test.h" 
%} 

%include "std_string.i" 
%include "test.h" 

然后我会期待你的示例代码工作。

根据std::string vs const char*,对于Python用户应该有非常小的可观察到的行为差异。 Python的本地字符串类型将被正确自动地转换为任何一种,所以我坚持的规则是,如果您使用的是C++,那么使用C++类型,除非有一个重要的原因。 POD-ness(或缺乏)不太可能成为界面的昂贵部分,甚至不太可能成为性能的瓶颈。

+0

这似乎给了我相同的结果。当我有权访问typedef别名的对象时,typedefs似乎工作。在字符串的情况下,我能够将字符串传递给代码并使其工作,但无法实例化别名类型。也许一个字符串是一个坏例子,因为它在大多数地方都可用。考虑'class C {...}; typedef C CAlias;'如果我在接口中有'C'声明,我可以实例化一个类'C'的对象并传递它,但是SWIG不允许我实例化一个类'CAlias'并将其称为它。这是预期的行为还是我错过了什么? – danielunderwood

+1

这是预期的行为 - 类型定义在C和C++中是'弱'的,所以这个(大部分)反映了语言那一边的行为。如果你真的想要,你可以使用'%pythoncode%{CAlias = C%}'来使'CAlias'成为一种Python类型,但是它并没有太大的收获。如果你想'CAlias'成为一个强类型的Python事物,你会想使用类似'BOOST_STRONG_TYPEDEF'的东西,并且我可以扩展来谈论包装。我怀疑,如果typedef的目的只是友好名称,那么你可能想要的所有内容都是SWIG的'%rename'指令来重命名基础类型。 – Flexo

+0

'%pythoncode'的方式工作得很好,但在语言之间并不是真正可移植的。具体来说,我意识到'typedef'不会翻译成很多语言。 '%rename'很好地与我对枚举的一些示例代码很好地工作,但对于我测试过的字符串没有做任何事情。我认为我的最佳选择是将“Message”变成完整的类,或者只是将文档直接用于目标语言。如果我大量使用typedefs,而不是在少数情况下,强类型定义可能是一个好主意。 – danielunderwood