2

I'm using pybind11 to access some functions which I wrote in C++ from python. I wish to return an initialized struct instance to python(from a class member function) so that I can access the instance values in python. I have provided a simplified version of my source file. One can reproduce the error with the following. This is the c++ wrapper

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "sum.h"
namespace py = pybind11;

PYBIND11_PLUGIN(GetSum) {

py::module mod("GetSum", "wrapping caltri");

mod.def("get_instance", &GetSum::get_instance, py::return_value_policy::copy, "get instance of out");

py::class_<GetSum, std::shared_ptr<GetSum>>(mod, "GetSum") 
  .def(py::init<>())
  .def("input", &GetSum::input);

return mod.ptr();
}

This is a part of the class header sum.h

   extern "C" {
#include "mesh.h"
}
#include<iostream>
#include<vector>

class GetSum {
 struct A out;

 public:
  GetSum();
  void input(std::vector<float>);
  struct A get_instance() {   
   return out; };  
  ~GetSum();

};

This is class definition sum.cpp

#include "sum.h"

GetSum::GetSum() {
 out.pointlist = nullptr;
}
void GetSum::input(std::vector<float> num){ 
  out.pointlist = new float[num.size()];   
  for(size_t i = 0; i < num.size(); i++) 
      *(out.pointlist+i) = num[i]; 
}

GetSum::~GetSum(){
  delete [] out.pointlist;
}

Struct definition: mesh.h

#include <stdio.h>

struct A {
 float *pointlist;
};

and this is how I was calling it in python.

import GetSum
m = GetSum.GetSum()
m.input([1.0,2.0])
GetSum.s = GetSum.get_instance()

After which I get the error: get_instance(): incompatible function arguments. The following argument types are supported: 1. (arg0: GetSum) -> A

Can someone help me figure out where I might be going wrong?

Thanks!

Surabhi Verma
  • 108
  • 1
  • 2
  • 11
  • sorry no. I have no idea about python, much less how to call a c++ function from python. Though, I was curious and wanted to help you to put all information that is needed into the question. As far as I can tell your question improved quite a lot. Now you just have to be lucky for someone to come along that can actually answer it ;) – 463035818_is_not_an_ai Aug 09 '17 at 15:51
  • ps: I will remove all that spammy comments... – 463035818_is_not_an_ai Aug 09 '17 at 15:52
  • @tobi303 Okay.. Actually when I passed the class object after changing the return type as static struct A.. It worked.. But then now when I add static before struct everywhere.. I get this error: a storage class can only be specified for objects and functions }; Any idea.. Do you think there is a bug in C++ side? – Surabhi Verma Aug 09 '17 at 16:06
  • sorry, forget about the `static`. I was just mislead by `get_instance` smelling like a singleton, which it is not. – 463035818_is_not_an_ai Aug 09 '17 at 16:08
  • There are several problems with your code. The binding to `get_instance` calls a non-static member function without a class. This is illegal as a member function needs access to the this pointer, which in turn is needed to access your member variable `out`. So your get_instance() binding must be part of the `GetSum` class definition. But that still is not enough as your out variable is of type `struct A`, which in turn contains a raw pointer. I'm not familiar enough with pybind11 to know to wrap A. What you probably want to do is to return a "view" to the data in A. ...cont... – Dov Grobgeld Aug 09 '17 at 19:46
  • ...cont... I suggest that you have a look at the buffer protocol binding of pybind11, which is built for exactly that. See: http://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html – Dov Grobgeld Aug 09 '17 at 19:47

1 Answers1

2

You need to declare struct A to pybind11 before it can be used as a return type by adding at minimum:

py::class_<A>(mod, "A")
  .def(py::init<>());

to your wrapper code. Further, since get_instance is not static, you need to call it as follows in your example python code:

GetSum.s = GetSum.get_instance(m)
Wim Lavrijsen
  • 3,453
  • 1
  • 9
  • 21