std::optional<> 的 SWIG Python 包装器
SWIG Python wrapper for std::optional<>
我正在编写一个 C++ 17 库,以及一个带有 SWIG (4.0.2) 的 python 3 包装器。库中的一些函数 return 是 std::optional<>
类型。我正在通过 SWIG 为 python 寻找 C++17 的 std::optional<T>
的包装器,但我找不到任何可以帮助我处理 T
的在线内容,一个实际类型(这个 T
与 template<typename T>
中的 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
但这 return 是(可能是预期的)错误:
swig/python detected a memory leak of type 'std::optional< T > *', no destructor found.
- 使用
%template(optional_T) std::optional<T>;
无效,因为 SWIG return 错误:
Error: Template 'optional' undefined.
- 我一直在查看官方文档中的类型映射,但无法从中得出结论。而且我什至不确定这些是否适用于我的情况。例如,此 github 存储库包含
std_optional.i
用于 float
%typemap(in) std::optional<float> %{
if($input == Py_None) {
= std::optional<float>();
}
else {
= std::optional<float>((float)PyFloat_AsDouble($input));
}
%}
%typemap(out) std::optional<float> %{
if() {
$result = PyFloat_FromDouble(*);
}
else {
$result = Py_None;
Py_INCREF(Py_None);
}
%}
但我不确定我是否可以使用类似的东西来包装 T
(class 的名称)。我试过了,但我不知道要在 ????
.
中放什么
%typemap(in) std::optional<T> %{
if($input == Py_None) {
= std::optional<T>();
}
else {
= std::optional<T>(T($input));
}
%}
%typemap(out) std::optional<lal::graphs::directed_graph> %{
if() {
$result = ????(*);
}
else {
$result = Py_None;
Py_INCREF(Py_None);
}
%}
问题 我如何用 SWIG(对于 Python)包装 std::optional<>
对于 T
其中 T
是class 的名称(如果可能的话)?我可以使用上面给出的方法制作自己的模板 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
的函数,其参数为 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
%}
我正在编写一个 C++ 17 库,以及一个带有 SWIG (4.0.2) 的 python 3 包装器。库中的一些函数 return 是 std::optional<>
类型。我正在通过 SWIG 为 python 寻找 C++17 的 std::optional<T>
的包装器,但我找不到任何可以帮助我处理 T
的在线内容,一个实际类型(这个 T
与 template<typename T>
中的 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
但这 return 是(可能是预期的)错误:
swig/python detected a memory leak of type 'std::optional< T > *', no destructor found.
- 使用
%template(optional_T) std::optional<T>;
无效,因为 SWIG return 错误:
Error: Template 'optional' undefined.
- 我一直在查看官方文档中的类型映射,但无法从中得出结论。而且我什至不确定这些是否适用于我的情况。例如,此 github 存储库包含
std_optional.i
用于float
%typemap(in) std::optional<float> %{
if($input == Py_None) {
= std::optional<float>();
}
else {
= std::optional<float>((float)PyFloat_AsDouble($input));
}
%}
%typemap(out) std::optional<float> %{
if() {
$result = PyFloat_FromDouble(*);
}
else {
$result = Py_None;
Py_INCREF(Py_None);
}
%}
但我不确定我是否可以使用类似的东西来包装 T
(class 的名称)。我试过了,但我不知道要在 ????
.
%typemap(in) std::optional<T> %{
if($input == Py_None) {
= std::optional<T>();
}
else {
= std::optional<T>(T($input));
}
%}
%typemap(out) std::optional<lal::graphs::directed_graph> %{
if() {
$result = ????(*);
}
else {
$result = Py_None;
Py_INCREF(Py_None);
}
%}
问题 我如何用 SWIG(对于 Python)包装 std::optional<>
对于 T
其中 T
是class 的名称(如果可能的话)?我可以使用上面给出的方法制作自己的模板 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
的函数,其参数为 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
%}