我建议分块建造
argv
其余代码中的元组。为了构造这个元组,需要遍历参数包,并为每个参数创建
PyObject
通过超载。C++ 11版本可以看起来像这样:
void to_py_tuple_impl(PyObject*, size_t) {}
template<typename ParamType, typename... ParamTypesTail>
void to_py_tuple_impl(PyObject* tpl, size_t index, const ParamType& param, const ParamTypesTail&... tail)
{
// error checking omitted for clarity
PyTuple_SetItem(tpl, index, to_py_object(param));
to_py_tuple_impl(tpl, index + 1, tail...);
}
template<typename... ParamTypes>
PyObject* to_py_tuple(const ParamTypes&... args)
{
PyObject* tpl = PyTuple_New(sizeof...(ParamTypes));
to_py_tuple_impl(tpl, 0, args...);
return tpl;
}
如果必须坚持C++ 11,则需要使用递归函数来迭代。
args
-那就是
to_py_tuple_impl
做。我已经把它包装好了
to_py_tuple
为了简单起见。
此代码调用
to_py_object
对于每个参数,以便将其转换为
PyObject*
并将该对象插入元组。
复制对象
可以重载以支持多种类型,例如:
PyObject* to_py_object(const std::string& str)
{
return PyUnicode_FromStringAndSize(str.c_str(), str.size());
}
PyObject* to_py_object(const char* str)
{
retrurn PyUnicode_FromString(str);
}
使用模板和
std::enable_if
:
// Converts all integer types:
template<typename T>
std::enable_if_t<std::is_integral<T>::value, PyObject*> to_py_object(T value)
{
return PyLong_FromLong(value);
}
// Converts all floating point types:
template<typename T>
std::enable_if_t<std::is_floating_point<T>::value, PyObject*> to_py_object(T value)
{
return PyFloat_FromDouble(value);
}
现在,你可以把它插到你的
py_call
功能:
template<typename T, typename... Targs>
void py_call(
const string &script,
const string &module,
T value, Targs... Fargs
)
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i;
pName = PyUnicode_DecodeFSDefault(script.c_str());
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, module.c_str());
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = to_py_tuple(Fargs...);
pValue = PyObject_CallObject(pFunc, pArgs);
...