簡體   English   中英

SWIG Python 包裝器用於 std::optional<>

[英]SWIG Python wrapper for std::optional<>

我正在使用 SWIG (4.0.2) 編寫 C++ 17 庫和 python 3 包裝器。 庫中的一些函數返回std::optional<>類型。 我一直在通過 SWIG 為 python 尋找 C++17 的std::optional<T>的包裝器,但我在網上找不到任何可以幫助我處理T的實際類型(這個T不一樣Ttemplate<typename T>一樣,在我的例子中是 class 的名稱)。 這是我嘗試過的,但沒有奏效。

  1. 我設法在定義兩個函數的std::optional<>中檢索結果:
%inline %{
bool is_optional_valid(const std::optional<T>& o) { return (o ? true : false); }
T get_data(const std::optional<T>& o) { return *o; }
%}

在 python 內部,我像這樣使用這些函數:

opt = ... # call to C++ function that returns an std::optional<>
if is_optional_valid(opt):
    contents = get_graph(opt)
    del opt
    return contents

del opt
return None

但這會返回(可能是預期的)錯誤:

swig/python detected a memory leak of type 'std::optional< T > *', no destructor found.
  1. 使用
%template(optional_T) std::optional<T>;

由於 SWIG 返回錯誤,因此不起作用:

Error: Template 'optional' undefined.
  1. 我一直在查看官方文檔中的類型圖,但我無法從中做出正面或反面。 我什至不確定這些是否適用於我的情況。 例如,這個 github 存儲庫包含一個std_optional.i for float
%typemap(in) std::optional<float> %{
    if($input == Py_None) {
        $1 = std::optional<float>();
    }
    else {
        $1 = std::optional<float>((float)PyFloat_AsDouble($input));
    }
%}
%typemap(out) std::optional<float> %{
    if($1) {
        $result = PyFloat_FromDouble(*$1);
    }
    else {
        $result = Py_None;
        Py_INCREF(Py_None);
    }
%}

但我不確定我是否可以使用這樣的東西來包裝一個T (類的名稱)。 試過了,不知道放什么???? .

%typemap(in) std::optional<T> %{
    if($input == Py_None) {
        $1 = std::optional<T>();
    }
    else {
        $1 = std::optional<T>(T($input));
    }
%}
%typemap(out) std::optional<lal::graphs::directed_graph> %{
    if($1) {
        $result = ????(*$1);
    }
    else {
        $result = Py_None;
        Py_INCREF(Py_None);
    }
%}

問題如何使用 SWIG(對於 Python)為T包裝std::optional<> ,其中T是 class 的名稱(如果可能的話)? 我可以 go 使用上面給出的方法制作我自己的模板 class。 像這樣的東西:

template<typename T>
class optional_wrapper {
    std::optional<T> m_optional_member;
public:
    // constructors...
    bool has_contents() const noexcept { return (m_optional_member ? true : false); }
    T get_contents() const noexcept { return *m_optional_member; }
};

最后,

namespace my_library {
%template(optional_wrapper_T) optional_wrapper<T>;
}

但我認為這不是 C++ 庫的最佳實踐,因為我將包裝現有類型,對於包裝類型沒有任何新內容(請告訴我您是否同意)。

任何幫助將不勝感激。 謝謝你。

第一種方法如下。 假設您在命名空間library中有一個名為call_to_function的 function ,其參數為ARGS (可以是int, intstd::string )。

首先,為std::optional<T>定義並實現一個模板包裝器:

%{
template<class T>
struct LB__optional {
    std::optional<T> m_opt;
    bool has_contents() const noexcept { return (m_opt ? true : false); }
    T contents() const noexcept { return *m_opt; }
};
%}

應該調用返回std::optional<>的函數:

// note that this does not compile
template<class T>
LB__optional<T> call_to_function(ARGS...) {
    __optional<T> r;
    r.m_opt = library::call_to_function(ARGS...);
    return r;
}

包裝LB__optionalcall_to_function

/* ---------- WRAP __optional ------------- */

template<class T>
struct LB__optional {
    std::optional<T> m_opt;
    bool has_contents() const noexcept { return (m_opt ? true : false); }
    T contents() const noexcept { return *m_opt; }
};

/* ---------- WRAP call_to_function ------------- */

template<class T> LB__optional<T> call_to_function(ARGS...);

/* ---------- INSTANTIATE LB__optional FOR SEVERAL TYPES ------------- */

%template(LB__optional_T) LB__optional<T>;

/* ---------- INSTANTIATE call_to_function FOR SEVERAL TYPES ------------- */

%template(call_to_function_T) call_to_function<T>;

添加一些 python 代碼:

%pythoncode %{

def call_to_function(instantiated_type, ARGS...):
    r"""
    Document your function please

    Parameters:
    ----------
    * `instantiated_type` :
        A type for which `call_to_function` has been instantiated in the `.i` file
    * `ARGS` :
        Not actual parameter, but rather a shorthand for the parameters that should be passed to `call_to_function`.
    """
    
    if instantiated_type not in [TYPES FOR WHICH ]:
        return None
    
    opt = globals()[ "call_to_function_" + instantiated_type ](ARGS...)
    # we now have access to the "optional" because it is a type that
    # python knows about since SWIG wrapped it (a wrapper for __optional)
    if opt.has_contents(): return opt.contents()
    return None
%}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM