Search code examples
pythonc++numpyboostboost-python

Using Boost Python Numpy ndarray as a Class member variable


I'm looking forward to pass an Python-Object to an Boost Python Class. This Object has an ndarray as attribute and I want to store this ndarray as a private member variable in this Class to use it later on. I could'n find a proper way to do this and I get Compiler Errors when declaring a boost::python::numpy::ndarray variable as private.

Here is my current code:

#include <boost/python/numpy.hpp>
#include <boost/python.hpp>

namespace p = boost::python;
namespace np = boost::python::numpy;

class FlatlandCBS {
  public:
    FlatlandCBS(p::object railEnv) : m_railEnv(railEnv) {

      // This is the Code I want to execute, so the ndarray is stored in the member varibale
      p::object distance_map = p::extract<p::object>(railEnv.attr("distance_map"));

      // Just a function which returns a ndarray (not the error)
      map = p::extract<np::ndarray>(distance_map.attr("get")());
    }

  private:
    p::object m_railEnv;
    // Can't use this and I get a Compiler Error
    np::ndarray map;
};


BOOST_PYTHON_MODULE(libFlatlandCBS) {       
  Py_Initialize();
  np::initialize();
  using namespace boost::python;

  class_<FlatlandCBS>("FlatlandCBS", init<object>());
}

The resulting Error message is:

error: no matching function for call to ‘boost::python::numpy::ndarray::ndarray()’

Here is also my CMakeLists.txt so you may reproduce this error:

cmake_minimum_required (VERSION 3.8)
project (libFlatlandCBS)


# Add all the files to the library so it can get created
ADD_LIBRARY(FlatlandCBS SHARED
                main.cpp)


# Set the Flags and the CXX command
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -Wall -Wextra -fconcepts")


INCLUDE_DIRECTORIES(include)

set(boostPython python)
find_package(PythonInterp 3.6 REQUIRED)
find_package(PythonLibs 3.6 REQUIRED)

include_directories(${PYTHON_INCLUDE_DIRS})

set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)  
set(Boost_USE_STATIC_RUNTIME OFF)
FIND_PACKAGE(Boost REQUIRED COMPONENTS system program_options numpy ${boostPython})


if(Boost_FOUND)

    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(FlatlandCBS ${Boost_LIBRARIES} ${PYTHON_LIBRARIES})

else()
    message(FATAL_ERROR "Could not find boost.")
endif()

Solution

  • So with the help from @unddoch it was finally possible to solve this problem. It turned out that it is not possible to use two extraxt functions in a row, but somehow the following is possible:

    FlatlandCBS(p::object railEnv) :
       m_railEnv(railEnv),
       m_map(
         p::extract<np::ndarray>(
           railEnv
             .attr("distance_map")
           .attr("get")()
         )
       )
    

    So if you want to extraxt multible values form the python object, just do as many .atrr() in a row.