2

I succeeded in binding this constructor

.def(py::init<const int, const int, const string *>())

My problem is when I have to use an array of strings, if I do like this

alph2=['x','y']
z=Dfa(3,2,alph2)

it fails saying:

TypeError: __init__(): incompatible constructor arguments. The
following argument types are supported:
gi_gipy.Dfa(arg0: int, arg1: int, arg2: unicode)

So I don't know how to pass from python something that resembles a const string*

  • I think the `alpha2` argument can be a `const std::list&` But I don't remember if that would cause any copying of the list. Moreover, you can't just pass a pointer, you need to specify the length of the array of char. Also, if the list just contains one letter characters, you can pass in one string like "xyz" instead of a list of char like ['x', 'y', 'z']. – R zu May 09 '18 at 15:22
  • The lenght of the array is the second parameter to the constructor. I need to separate characters like ['x','y','z']. If I do as you say, to replace const string* in the c++ code with const std::list&, it says "no type named 'list' in namespace 'std'" –  May 09 '18 at 15:31
  • The python list already has a len. So there is no need for the 2nd parameter. – R zu May 09 '18 at 15:33
  • `#include` and `#include` – R zu May 09 '18 at 15:33
  • First of all thank you for your attention. The problem here is that I have a functioning C++ library that I'm not allowed to change. So here the constructor is the one I indicated in the first post, with 3 parameters: 2 integers, and a const string*. If I replace const string* with list, as you say, the compiler says that there is no matching constructor for initialization of 'Dfa'. So the problem is that I'm searching some way in python to express a thing similar to a C++ const string*. In other words, I have this constructor which I bind to correctly, but I don't know how to call it from py –  May 09 '18 at 17:17
  • You can 1. write one extra function at c++ side `Dfa_pybind11_wrapper(const int, const std::list&)` that calls `Dfa` 2. Change the python code to pass `int`, `int`, and `str` to the c++ function. For 2, see http://pybind11.readthedocs.io/en/stable/advanced/cast/strings.html – R zu May 09 '18 at 17:37
  • The second method doesn't work, because the c++ constructor is expecting a pointer to string, so I can't pass a string. For the wrapper solution I tried with this code: .def(py::init([](int n_state,int dim_alf, std::list& alph){ std::string* alfabeto=new std::string[dim_alf]; std::list::iterator it=alph.begin(); for(int i=0;it!=alph.end();++i,++it) alfabeto[i]=*it; Dfa::Dfa(n_state,dim_alf,alfabeto); })) The logic is, from python side I'm asking a list and then I call the right constructor, building the correct pointer to string –  May 10 '18 at 15:02
  • But I guess I'm missing the point here, because I'm getting two errors: cannot pass expression of type 'void' to variadic function and static_assert failed "pybind11::init(): init function must return a compatible pointer, holder, or value" –  May 10 '18 at 15:03
  • Ask new question and show more code. Instead of including the whole library with the `Dfa` function, do the following. Make a dummy c++ function that does nothing but takes in the same kind of arguments as your c++ function. Show the cpp file with the `.def`. Only a few people would read 8 comments. You can pass a python unicode string to a c++ function that accepts a `const char *s` pointer because pybind11 takes care of the conversion. Just look at the first example in http://pybind11.readthedocs.io/en/stable/advanced/cast/strings.html – R zu May 10 '18 at 15:25
  • If you can wait, I might give a complete answer 2 days later. – R zu May 10 '18 at 15:28
  • Again, thank you a lot. I asked a new question: https://stackoverflow.com/questions/50279180/pybind11-passing-a-string-argument-to-a-constructor Take your time don't worry, any help is super appreciated :) –  May 10 '18 at 18:20

1 Answers1

1

main.cpp:

#include <iostream>
#include <list>
#include "pybind11/pybind11.h"

void Dfa(const int n_state, const std::size_t size, const char* alpha) {
    std::cout << "n_state: " << n_state << "\n";
    std::cout << "size: " << size << "\n";
    std::cout << "alpha: " << alpha << "\n";
}

void dfa_wrapper(int n_state, std::string alpha) {
    // Copy the python unicode string 
    // and make a c++ std::string.
    // Modifying this copy won't change
    // the original python string.
    Dfa(n_state, alpha.size(), alpha.data());
}

PYBIND11_MODULE(_cpp, m) {
    m.def("dfa", &dfa_wrapper, "Wrapper of your Dfa::dfa");
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.9)
project(test_pybind11)

set(CMAKE_CXX_STANDARD 11)

# Find packages.
set(PYTHON_VERSION 3)
find_package( PythonInterp ${PYTHON_VERSION} REQUIRED )
find_package( PythonLibs ${PYTHON_VERSION} REQUIRED )

# Download pybind11
set(pybind11_url https://github.com/pybind/pybind11/archive/stable.zip)

set(downloaded_file ${CMAKE_BINARY_DIR}/pybind11-stable.zip)
file(DOWNLOAD ${pybind11_url} ${downloaded_file})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${downloaded_file}
        SHOW_PROGRESS)
file(REMOVE ${downloaded_file})

set(pybind11_dir ${CMAKE_BINARY_DIR}/pybind11-stable)
add_subdirectory(${pybind11_dir})
include_directories(${pybind11_dir}/include)

# Make python module
pybind11_add_module(_cpp main.cpp)

Python 3 test:

>>> import _cpp
>>> _cpp.dfa(1, "xyz")
n_state: 1
size: 3
alpha: xyz
R zu
  • 2,034
  • 12
  • 30