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++ 模板类型的嵌套命名空间的主要内容,如果未能解决你的问题,请参考以下文章

Boost.Python 如何拥有 C++ 类?

匹配任何类型参数的 C++ 可变参数模板模板参数

将派生类型的对象从 python 传递到 C++ 函数时会出现 Boost Python 运行时错误,该函数期望将 shared_ptr 传递给基类型

Boost.Python 从类型创建句柄

如何使用 Boost Python 从 C++ bool 转换为 Python boolean?

*.pyd 库中的 C++ Boost Python 方法不起作用