问题
I would like to bind a C++-function with PyBind11. The problem is that this functions has an argument with a double pointer and the compiler raises an error
error: cannot initialize a parameter of type 'char **' with an rvalue of type 'typename make_caster<char **>::cast_op_type<typename std::add_rvalue_reference<char**>::type>' (aka 'char *')
.
Specifically the code look like this:
#include <pybind11/pybind11.h>
#include <iostream>
namespace py = pybind11;
void parse_args(int argn__, char** argv__)
{
for(int i = 1; i < argn__; ++i)
{
std::cout<< argv__[i];
}
}
PYBIND11_MODULE(argv_bind, m) {
m.def("parse_args", &parse_args);
}
回答1:
For non-simple argument types (e.g. like your char **
) you'll have to wrap the function itself, where your wrapper provides the logic to go from a simpler type or a Python object to the desired type.
In this case, char *
are actually a pretty unsafe type to work with, since it doesn't get memory cleanup; to make this work robustly you'll need to take std::string
s, from which you can then access the char *
via the c_str()
method. (In pybind11, even when you take char *
arguments, those are really just pointers into std::string
arguments: the Python API deliberately doesn't let callers access the internal storage of Python strings).
So then you just want to combine it with a type that can itself expose the whole thing as a char **
, which is pretty much what std::vector
is designed to do. Here's a wrapper that would fit your example code:
#include <pybind11/stl.h>
m.def("parse_args", [](std::vector<std::string> args) {
std::vector<char *> cstrs;
cstrs.reserve(args.size());
for (auto &s : args) cstrs.push_back(const_cast<char *>(s.c_str()));
return parse_args(cstrs.size(), cstrs.data());
});
(If your parse_args
actually takes a const char **
you can drop the const_cast
).
来源:https://stackoverflow.com/questions/49195418/pybind11-binding-a-function-that-uses-double-pointers