简体   繁体   中英

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. Ie 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 ?

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>;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM