[英]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
不一樣T
與template<typename T>
一樣,在我的例子中是 class 的名稱)。 這是我嘗試過的,但沒有奏效。
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.
%template(optional_T) std::optional<T>;
由於 SWIG 返回錯誤,因此不起作用:
Error: Template 'optional' undefined.
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, int
或std::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__optional
和call_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.