okkhoy
okkhoy

Reputation: 1338

SWIG c++ to python : vector problems

I am following the documentation here: http://www.swig.org/Doc3.0/Library.html#Library_stl_cpp_library to write a wrapper to a simple example code involving vectors.

Here is the header file:

### word.h ###
#include<string>
#include<vector>

class Word{
public:
    Word(std::string word, int numWords, std::vector<double> &values);
    ~Word();

    void updateWord(std::string newWord);
    std::string getWord();
    void processValues();

private:
    std::string theWord;
    int totalWords;
    std::vector<double> values;
};

And the source file:

### word.cpp ###
#include "word.h"
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <time.h>

Word::Word(std::string word, int numWords, std::vector<double> &values) :
    theWord(word), totalWords(numWords), values(values){
    // TODO: constructor
}

Word::~Word() {
    // TODO: destructor
}

void Word::updateWord(std::string newWord) {
    this->theWord = newWord;
}

std::string Word::getWord() {
    return this->theWord;
}

void Word::processValues() {
    values.resize(totalWords);
    // do something with values here
}

/*  
    rest of the code that uses the other imports
*/

Here is the interface file:

### word.i ###
%module word
%{
#include "word.h"
%}

%include "std_string.i"
%include "std_vector.i"

namespace std {
    %template(vectord) vector<double>;
}

%include "word.h"

My compilation steps are as follows:

swig -c++ -python word.i
g++ -c -fpic word.cpp word_wrap.cxx -I/usr/include/python2.7
g++ -shared word.o word_wrap.o -o _word.so -lstdc++

The compilation goes through without any errors. However, on trying to create the object in Python I get the following error:

In [1]: import word

In [2]: w = word.Word('test', 10, [10.2])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-ee2e5c406fd9> in <module>()
----> 1 w = word.Word('test', 10, [10.2])

/home/anarayan/workspace/swig-learn/word.pyc in __init__(self, word, numWords, values)
    276 
    277     def __init__(self, word, numWords, values):
--> 278         this = _word.new_Word(word, numWords, values)
    279         try:
    280             self.this.append(this)

TypeError: in method 'new_Word', argument 3 of type 'std::vector< double,std::allocator< double > > &'

A bit of searching online leads me to believe that using the template in the SWIG definition solves this problem.

However, in my case it hasn't. Could you please point me in the right direction?

Upvotes: 3

Views: 1676

Answers (1)

Henri Menke
Henri Menke

Reputation: 10939

It doesn't work because you passing the vector by reference. If you instead pass by value or by const reference SWIG knows what to do and generates the correct code. Simply changing the type in the declaration and defintion of

Word(std::string word, int numWords, std::vector<double> const &values);

is sufficient.

$ swig -c++ -python word.i
$ g++ -c -fpic word.cpp word_wrap.cxx -I/usr/include/python2.7
$ g++ -shared word.o word_wrap.o -o _word.so -lstdc++
$ python
Python 2.7.13 (default, Nov 24 2017, 17:33:09) 
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import word
>>> w = word.Word('test', 10, [10.2])

In this case you can apply the above adjustments because you don't need values to be a bare reference. If a reference is needed more work is required and you have to write your own typemap (and probably your own container).

Upvotes: 2

Related Questions