When you extend a class with %extend
you can't really add any new member variables, only member functions. It will assume the existence of a get/set function if you do this in %extend
.
The reason for this is that the storage (i.e. memory) for the new member variables would have to live somewhere, but there's no obvious safe place to put it. You can't modify the original C++ class
, because if you do you'll end up with undefined behaviour when some other, pre-compiled code uses the old definition of the class; there's no way to retrospectively apply the new definition. You can't put it in the proxy that gets generated in the target language, because there isn't a 1:1 mapping between instances of C++ classes and proxies in the target language. (Consider two functions that both return the same global instance via a pointer for the trivial example of how this may occur).
If you wanted to implement the get/set functions to do something useful (e.g. here I used a global map to store the extra data) you don't want to implement them inside %extend
For example, given test.hh with just:
template <typename T>
struct Foo {};
You can use a std::map
to do what you're trying to do by writing your own gets and sets as free functions in the wrapper - %{ %}
just passes the code straight through:
%module test
%include "test.hh"
%{
#include "test.hh"
%}
%{
#include <map>
static std::map<Foo<int>*, double> extra_stuff;
const double& Foo_Sl_int_Sg__x_get(Foo<int>* f) {
return extra_stuff[f];
}
void Foo_Sl_int_Sg__x_set(Foo<int>* f, const double& d) {
extra_stuff[f] = d;
}
%}
%template(FooInt) Foo<int>;
%extend Foo<int> {
double x;
}
The get/set functions are mangled by SWIG's own mangling system because it's a template. I just looked in the generated wrapper class to see what they were called. (I think there might be a smarter way to do that but I couldn't figure it out from the documentation yet). If it wasn't a template the name of the functions would be much simpler.
Note that there's no provision here for ever removing entries from this map - it will just grow indefinitely. (You can work around that for example by providing a typemap that calls an extra function at the end of an Object's life). You also need to be careful about threads.
Since you didn't specify what language you were using I tested the above code with Java:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
FooInt f = new FooInt();
f.setX(0.1);
System.out.println(f.getX());
}
}
Alternatively if you really want to you can write code to ensure that there is a unique single proxy instance in the the target language, by writing a typemap that checks if an proxy has been created instead of always creating one, but that raises issues with reference counting and thread safety that are hard to address efficiently and generically, which is why it's not the default behaviour.
The simplest workaround in a lot of cases (e.g. iterators in the target language) though is to use %inline
to declare and define and wrap all at once an entirely new extra class that that provides the functionality you want.