我正在尝试使用pybind11(v2.2.2 +)创建python绑定,并且无法弄清楚如何调用具有单个std :: initializer_list参数的C函数。
void list_ints(std::initializer_list<int>)
pybind11绑定是:
m.def("list_ints", &list_ints)
从python,我试图像这样调用:
list_ints(1, 2, 3)
以下是使用llvm在MacOS上使用-std=C++14
编译的示例C代码:
#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
using namespace std;
namespace py = pybind11;
void list_ints(const std::initializer_list<int> &il) {
std::cout << "Got to list_ints ..." << std::endl;
for (const auto &elem : il)
std::cout << to_string(elem) << " ";
std::cout << std::endl;
};
PYBIND11_MODULE(initializer, m) {
m.def("list_ints", &list_ints);
m.def("list_ints", (void (*) (const std::initializer_list<int>&)) &list_ints);
# This is the only binding that seems to work .. sort of.
m.def("list_ints", (void (*) (const int &a, const int &b)) &list_ints);
}
python代码包含结果的描述:
from initializer import list_ints
try:
# Fails with: TypeError: Incompatible function arguments
print("Calling list_ints(1, 2, 3)")
list_ints(1, 2, 3)
except TypeError as err:
print(err)
# Call succeeds but function Seg Faults!
print("Calling list_ints(1, 2)")
list_ints(1,2)
此测试代码演示了与定义为const int &a, const int &b
的参数的绑定是否匹配并调用list_ints函数,但由于在访问参数时发生了seg错误,因此显然不正确。
$ python initializer.py
Calling list_ints(1, 2, 3)
list_ints(): incompatible function arguments. The following argument types are supported:
1. (arg0: std::initializer_list<int>) -> None
2. (arg0: std::initializer_list<int>) -> None
3. (arg0: int, arg1: int) -> None
Invoked with: 1, 2, 3
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.
Calling list_ints(1, 2)
Got to list_ints ...
Segmentation fault: 11
有没有办法从Python绑定和调用void list_ints(std::initializer_list<int>)
?
答案 0 :(得分:0)
我从jagerman@github.com收到了pybind11 repo的答案:
它不受支持,我相信,不支持:初始化列表是故意不透明的类型,只能由C ++编译器构建,而不是由C ++代码构建 - 这意味着它是不可能的我们接受它。
有关详细信息,请参阅C++11 is it possible to construct an std::initializer_list?的答案。
至于你的绑定代码,你基本上reintepret_cast
将你的函数转换为一个采用不同类型的函数。 Pybind构造一个std::vector<int>
然后传递它作为函数参数,但函数认为它得到std::initializer_list
- 然后坏事发生。对于参数,它基本上是auto &il = reintepret_cast<std::initializer_list<int> &>(v)
,其中v
是std::vector<int>
。
答案 1 :(得分:0)
尽管作出了“无法支持”的论点,但使用cppyy(http://cppyy.org)却相当简单,但需要注意的是,您需要使用list_ints(1, 2, 3)
来代替list_ints((1, 2, 3))
。就是使用实际的python集合,而不是3个参数(比较numpy数组的初始化方式;是一样):
import cppyy
cppyy.cppdef(r"""void list_ints(std::initializer_list<int> ll) {
for (auto i: ll)
std::cerr << i << '\n';
}""")
cppyy.gbl.list_ints((1, 2, 3))
会打印出预期的内容:
1
2
3