F.L.
F.L.

Reputation: 559

Wrapping C++ template constructors in template class

I have a complex c++ library that I need to expose to a java android application. This C++ library consists of standard C++ classes and C++ class templates.

One of the templates in the library has a template constructor.

Because an example is worth a thousand words:

namespace NS1 {

    template < class T >
    class Bar {

    protected:

        T mVal;

    public:

        template< class OtherType >
        Bar (const Bar<OtherType>& pOther) {
            mVal = pOther.mVal;
        }

    };

    class A {
    };

    class B : public A {};
}

I wrap these using the following swig interface file snippet:

%extend NS1::Bar< A > {
    %template(Abar) NS1::Bar::Bar<NS1::A>;
    %template(ABar) NS1::Bar::Bar<NS1::B>;
};
%template(ABar) NS1::Bar< NS1::A >;

%extend NS1::Bar<B> {
    %template(BBar) NS1::Bar::Bar<NS1::B>;
};
%template(BBar) NS1::Bar<NS1::B>;

I'd like the wrapper to include wrapping of the template constructor:

public class ABar {
    public ABar (ABar other) {...}
    public ABar (BBar other) {...}
}

This is alright, the issue is that the extend directive seems to ignore the template parameter, and extends every instantiation of the Bar template with these. I.e. the BBar java class looks like this:

public class BBar {
    public BBar (ABar other) {...}
    public BBar (BBar other) {...}
}

Which is incorrect in that case.

How can I "bind" the extend to a specific template instantiation ?

Note:

Using the namespace in the %extend directive (%extend NS1::Bar<NS1::A>{...}) causes an assert in Swig to fail.

I have tried with both swig 2.0.12 and 3.0.8

Any clue anyone ?

Upvotes: 4

Views: 573

Answers (1)

I got this to work as you're hoping with SWIG 3.x. It's definitely overly sensitive here, I think it came down to three things:

  1. Be consistent with namespaces. Either always use the fully qualified version, or always write everything inside the namespace in the .i file.
  2. Refer to constructors as Bar instead of Bar::Bar inside %extend. (Per the std::pair example in the documentation)
  3. Instantiate all your templates before extending any selectively.

I'm not completely sure if all of those things are mandatory, but they certainly were sufficient to make it work here. So my working example looks like:

%module test

%include "test.hh"

%template(ABar) NS1::Bar< NS1::A >;
%template(BBar) NS1::Bar<NS1::B>;

namespace NS1 {

%extend Bar< A > {
    %template(ABar) Bar<A>;
    %template(ABar) Bar<B>;
};

%extend Bar<B> {
    %template(BBar) Bar<B>;
};
} // NS1

With test.hh being the C++ code you showed copied verbatim this generates sane Java/JNI.

The following would also work too though, following the above guidlines:

%module test

%include "test.hh"

%template(ABar) NS1::Bar< NS1::A >;
%template(BBar) NS1::Bar<NS1::B>;

%extend NS1::Bar<NS1::A> {
    %template() Bar<NS1::A>;
    %template() Bar<NS1::B>;
};

%extend NS1::Bar<NS1::B> {
    %template() Bar<NS1::B>;
};

Upvotes: 1

Related Questions