2016-11-15 2 views
0

나는 SWIG가있는 프로젝트에서 파이썬 코드를 생성했습니다. 나는 이 std::string에서 Message이고 say(Message) 기능이 있습니다. 파이썬에서 문자열로 say을 호출 할 수 있습니다. Message 유형의 변수를 만들 수 있고 싶고 Message 유형을 파이썬 래퍼가 아닌 라이브러리로 내보내고 싶습니다. 여기 내 파일은 다음과 같습니다SWIG에서 typedefd 유형의 변수 만들기

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; 
} 

테스트 테스트

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

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

파이썬 예를

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' 

내 실제 사용 사례에는 다른 유형 (주로 열거 형)에 대한 typedef가 포함되어 있습니다. 이러한 경우에는 다른 처리 방법이 필요한지 궁금합니다. SWIG 바인딩 클래스의 객체를 래핑하고 SWIG 생성 클래스를 수정하거나 SWIG typemap을 사용할 수 있다고 생각합니다. 그러나 이것이 공통적이라고 생각할 수있는 원형 솔루션입니다. 상태.

string 헤더의 코드에 액세스하는 데 문제가있을 수 있다고 생각했지만 int과 같은 typedef를 시도하면 동일한 문제가 발생합니다.

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

그리고 테스트 테스트에 해당하는 %template 지침 :

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

불행하게도,이 몇 가지가있는 것

내 가장 좋은 방법은 지금까지의 래퍼 템플릿이었다한다 지금까지의 단점 :

  • operator()을 호출하십시오. 즉, test.Message('a')()을 호출해야합니다.
  • 일부 조건부 컴파일을 사용하거나 wrapper를 typedef와 다른 이름으로 지정해야합니다. 그렇지 않은 경우 test.say은 래퍼 또는 문자열을 허용하지 않으므로 전혀 사용할 수 없습니다.
  • 구성시 오류가있는 열거 형과 작동하지 않는 것 같습니다.

나는 또한 내가 영리한 것으로 바꿀지도 모른다고 생각했다. operator*은 감싸는 것을 되돌려 놓았지만, 어쨌든 반환 된 것은 감싸는 듯했다.

+0

'std :: string'은'POC' 타입이 아니고 메모리가 힙에 할당 되었기 때문에'stat char *'를 사용하는 것이 좋을 것입니다. 힙은 디버그 이건 릴리즈 이건 다르게 작동합니다. 나는'% 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

일반적으로 SWIG typedef에서 "그냥 작동해야합니다". (템플릿이 인스턴스화 될 때 템플릿이 예상대로 작동하지 않는다는 것을 알고 있지만 여기에는 문제가 없습니다.)

예를 들어, 사용자의 문제는 단순히 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::stringconst char*의 관점에서 볼 때, Python 사용자에게는 관찰 가능한 동작 차이가 거의 없어야합니다. 파이썬의 네이티브 문자열 타입은 둘 중 하나를 위해 자동적으로 자동적으로 변환 될 것입니다. 그래서 내가 지키고 싶은 규칙은 C++을 사용한다면 무시할 이유가 없다면 C++ 타입을 사용하십시오. POD-ness (또는 인터페이스가없는 인터페이스)는 인터페이스의 값 비싼 부분이 아니며 성능에있어 병목 현상이 적습니다.

+0

이것은 나에게 같은 결과를주는 것 같습니다. typedef는 typedef가 별명을 가진 객체에 액세스 할 때 작동하는 것 같습니다. 문자열의 경우 문자열을 코드에 전달하여 작동 시키지만 별칭 유형을 인스턴스화 할 수는 없습니다. 아마도 문자열은 대부분의 장소에서 사용할 수 있으므로 나쁜 예였습니다. '클래스 C {...}; typedef C CAlias;'인터페이스에'C' 선언이 있으면'C' 클래스의 객체를 인스턴스화하고 전달할 수 있지만 SWIG는'CAlias' 클래스를 인스턴스화하여 호출하도록 허용하지 않습니다. 예상되는 행동입니까, 아니면 뭔가 빠졌습니까? – danielunderwood

+1

예상되는 동작입니다. typedef는 C 및 C++에서 '약함'이므로이 언어는 언어의 측면에서의 동작을 대부분 반영합니다. 정말로 원한다면'% pythoncode % {CAlias ​​= C %}'를 사용하여''CAlias''를 파이썬 타입으로 만들 수 있습니다. 'CAlias'가 강하게 타입 화 된 파이썬이되도록하려면'BOOST_STRONG_TYPEDEF'와 같은 것을 사용하고 싶습니다. 그리고 그것을 래핑하여 확장 할 수 있습니다. typedef의 목적이 친숙한 이름 일 때 SWIG의'% rename' 지시어가 기본 유형의 이름을 바꿀 수 있다고 생각합니다. – Flexo

+0

'% pythoncode '방식은 꽤 잘 작동하지만, 언어 간에는 이식성이 없습니다. 구체적으로 말하자면, typedef는 많은 언어로 번역되지 않는다는 것을 깨달았습니다. '% rename'은 열거 형에 대한 예제 코드와 잘 맞지만, 테스트 한 것에서는 문자열을 사용하지 않습니다. 최선의 선택은'Message'를 전체 클래스로 만들거나 그냥 문서를 대상 언어로 직접 사용하는 것입니다. 몇 가지 경우가 아니라 typedef를 많이 사용하는 경우 강력한 typedef를 사용하는 것이 좋습니다. – danielunderwood