Boost.Python:匹配 C++ 模板类型的嵌套命名空间
Posted
技术标签:
【中文标题】Boost.Python:匹配 C++ 模板类型的嵌套命名空间【英文标题】:Boost.Python : nested namespace matching C++ template types 【发布时间】:2019-12-28 13:37:15 【问题描述】:尝试使用 Boost.Python 将 python numpy 数组传递给 C++,在 C++ 中处理它们,并将处理结果返回给 python:由于数组的类型是在 C++ 端模板化的,它应该匹配 python 端的嵌套命名空间.
尽管进行了多次测试/谷歌搜索,但仍未找到解决方案。
错误:“Boost.Python.ArgumentError python 参数类型与 C++ 签名不匹配”:任何线索?...
>> more dummy.hpp dummy.cpp dummy.py
::::::::::::::
dummy.hpp
::::::::::::::
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <iostream>
namespace bp = boost::python;
namespace np = boost::python::numpy;
template<typename FD>
class dummy
public:
dummy()
Py_Initialize();
np::initialize();
mean = 0.;
;
int doStuffs(np::ndarray & A)
int szA = A.shape(0);
FD * ptrA = reinterpret_cast<FD*>(A.get_data());
for (int i = 0; i < szA; ++i)
std::cout << "dummy::doStuffs - " << i << " : " << ptrA[i] << std::endl;
mean += ptrA[i];
mean /= szA;
std::cout << "dummy::doStuffs, mean " << mean << std::endl;
return 0;
;
FD mean;
;
template<typename FD>
void exportDummy(std::string const & nested)
std::string module = "dummy." + nested;
bp::object pyModule(bp::handle<>(bp::borrowed(PyImport_AddModule(module.c_str()))));
bp::scope().attr(nested.c_str()) = pyModule;
bp::scope pyScope = pyModule;
bp::class_<dummy<FD>, boost::noncopyable>(nested.c_str())
.def ("doStuffs", &dummy<FD>::doStuffs)
.def_readonly ("mean", &dummy<FD>::mean);
;
::::::::::::::
dummy.cpp
::::::::::::::
#include <boost/python.hpp>
#include <dummy.hpp>
namespace bp = boost::python;
BOOST_PYTHON_MODULE(dummy)
// Specify that this module is actually a package.
bp::object package = bp::scope();
package.attr("__path__") = "dummy"; // Setting the __path__ attribute on the module to the name of the module.
// Create modules.
exportDummy<float>("float");
::::::::::::::
dummy.py
::::::::::::::
#!/usr/bin/env python
from __future__ import print_function
import numpy as np
from scipy import sparse
n = 4
one = np.array([ 1]*n)
data = np.array([2.*one, -1.*one, -1.*one])
diags = np.array([0, 1, -1])
A = sparse.spdiags(data, diags, n, n)
print("python A ", A.toarray())
import dummy
dummyFloat = dummy.float.float()
dummyFloat.doStuffs(A)
print("python mean", dummyFloat.mean)
我得到:
>> make
g++ -I/usr/include/python2.7 -I. -fPIC -shared -o dummy.so dummy.cpp -lboost_numpy -lboost_python -lpython2.7
>> python dummy.py
python A [[ 2. -1. 0. 0.]
[-1. 2. -1. 0.]
[ 0. -1. 2. -1.]
[ 0. 0. -1. 2.]]
Traceback (most recent call last):
File "dummy.py", line 17, in <module>
dummyFloat.doStuffs(A)
Boost.Python.ArgumentError: Python argument types in
float.doStuffs(float, dia_matrix)
did not match C++ signature:
doStuffs(dummy<float> lvalue, boost::python::numpy::ndarray lvalue)
【问题讨论】:
【参考方案1】:找到解决方案!
>> more dummy.cpp dummy.hpp dummy.py
::::::::::::::
dummy.cpp
::::::::::::::
#include <boost/python.hpp>
#include <complex>
#include <dummy.hpp>
namespace bp = boost::python;
BOOST_PYTHON_MODULE(dummy)
bp::object package = bp::scope();
package.attr("__path__") = "dummy";
exportDummy<float>("float");
exportDummy<complex<float>>("complexFloat");
::::::::::::::
dummy.hpp
::::::::::::::
#include <boost/python.hpp>
#include <boost/python/numpy.hpp>
#include <iostream>
namespace bp = boost::python;
namespace np = boost::python::numpy;
using namespace std;
template<typename FD>
class dummy
public:
dummy()
Py_Initialize();
np::initialize();
mean = 0.;
;
int doStuffs(np::ndarray & A)
int szA = A.shape(0);
FD * ptrA = reinterpret_cast<FD*>(A.get_data());
for (int i = 0; i < szA; ++i)
std::cout << "C++ - dummy::doStuffs - " << i << " : " << ptrA[i] << std::endl;
mean += ptrA[i];
mean /= szA;
return 0;
;
FD mean;
;
template<typename FD>
void exportDummy(std::string const & nested)
std::string module = "dummy";
bp::object pyModule(bp::handle<>(bp::borrowed(PyImport_AddModule(module.c_str()))));
bp::scope pyScope = pyModule;
pyScope.attr(nested.c_str()) = bp::class_<dummy<FD>, boost::noncopyable>(nested.c_str())
.def ("doStuffs", &dummy<FD>::doStuffs)
.def_readonly("mean", &dummy<FD>::mean)
;
;
::::::::::::::
dummy.py
::::::::::::::
#!/usr/bin/env python
from __future__ import print_function
import numpy as np
import dummy
A = np.array([1, 2, 3], dtype='float32')
print("python A ", A)
df = dummy.float()
df.doStuffs(A)
print("python mean", df.mean)
A = np.array([1+2j, 3+4j, 5+6j], dtype='complex64')
print("python A ", A)
dcf = dummy.complexFloat()
dcf.doStuffs(A)
print("python mean", dcf.mean)
我明白了:
>> make
g++ -I/usr/include/python2.7 -I. -fPIC -shared -o dummy.so dummy.cpp -lboost_numpy -lboost_python -lpython2.7
>> python dummy.py
python A [1. 2. 3.]
C++ - dummy::doStuffs - 0 : 1
C++ - dummy::doStuffs - 1 : 2
C++ - dummy::doStuffs - 2 : 3
python mean 2.0
python A [1.+2.j 3.+4.j 5.+6.j]
C++ - dummy::doStuffs - 0 : (1,2)
C++ - dummy::doStuffs - 1 : (3,4)
C++ - dummy::doStuffs - 2 : (5,6)
python mean (3+4j)
【讨论】:
以上是关于Boost.Python:匹配 C++ 模板类型的嵌套命名空间的主要内容,如果未能解决你的问题,请参考以下文章
将派生类型的对象从 python 传递到 C++ 函数时会出现 Boost Python 运行时错误,该函数期望将 shared_ptr 传递给基类型