1

I have the following C++ library, which I want to use in Java using Swig to generate the necessary glue code. However, I am finding it difficult to send a vector of user-defined objects to C++ which have some data. I tried using std_vector.i but Swig still generates SWIGTYPE_p_std_VectorT_namespace_Beer which somehow mismatch with the SwigVector instance.

%module pub

%include "std_vector.i"
namespace std {
  %template(SwigVector) std::vector<Beer>;
}  

%{
#include "Pub.h"
#include "MyPub.h"
#include "Beer.h"   
using namespace pub;
%}

%include "Pub.h"    
...
namespace order{
class OrderTracker
{
public:
    class OrderListener
    {
    public:
        OrderListener() : orderTracker_{nullptr} {}
        virtual void onNewOrder(OrderTracker&) = 0;
    private:
        friend class OrderTracker;
        void setOrderTracker(OrderTracker* orderTracker)
        {
            orderTracker_ = orderTracker;
        }
        OrderTracker* orderTracker_;
    };
    void addOrderListner(OrderListener&);
};
class Status;
...
} // end namespace order

namespace pub{
class Pub
{
public:
    virtual ~Pub() = default;
    virtual void initOrder() = 0;
    virtual std::vector<Beer> getBeers() = 0;
    ...
};

class MyPub : public Pub
{
public:
    void initOrder() override;
    std::vector<Beer> getBeers() override;
    void generateBill() override;
    ...
private:
    order::OrderTracker* orderTracker;
    class MyOrderListener : public order::OrderTracker::OrderListener
        {
        public:
            explicit MyOrderListener(MyPub* pub) { this->pub_ = pub; }
            ~MyOrderListener() { delete pub_; }
            void onNewOrder(order::OrderTracker& orderTracker) = override;
        private:
            MyPub* pub_;
        };
        MyOrderListener* listener; // orderTracker->addOrderListner(listener);
};

enum class BeerType
{
    House   ,
    Lager   ,
    Pale    ,
    IPA
};

class Beer
{
public:
    Beer() : type{BeerType::House}, price{5.99} {}
    ~Beer() = default;

    BeerType getType() {return this->type};
    float getBeerPrice() {return this->price};

private:
    BeerType type;
    float price;

    void setPrice(float price);
    void setType(BeerType type);
};
} // namespace pub ends

following is the desired behavior that I am expecting.

public class main
{
    public static void main(String argv[])
    {
        System.loadLibrary("mypub");
        MyPub pub = new MyPub();
        pub.initOrder();
        while(money > 1000)
        {
         SwigVector beers = pub.getBeers();
            for(int i =0; i<beers.size(); ++i){
            beers[i].getPrice();
            }
        }
   }
}

P.S. Most of the questions either wrap primitive data types or are pre-Swig 3.0 versions. If I did miss any please spare the mistake. Any help would be greatly appreciated.

getchar
  • 75
  • 9

1 Answers1

1

This should work. Order matters. Make sure to define classes before using them:

%module pub

%include "std_vector.i"

%inline %{

enum class BeerType
{
    House,
    Lager,
    Pale,
    IPA
};

class Beer
{
public:
    Beer() : type{BeerType::House}, price{5.99f} {}
    ~Beer() = default;

    BeerType getType() {return this->type; }
    float getBeerPrice() {return this->price; }

private:
    BeerType type;
    float price;

    void setPrice(float price) { this->price = price; }
    void setType(BeerType type) { this->type = type; }
};

%}

%template(SwigVector) std::vector<Beer>;

%inline %{

class Pub
{
public:
    virtual ~Pub() = default;
    virtual void initOrder() = 0;
    virtual std::vector<Beer> getBeers() = 0;
    virtual void generateBill() = 0;
};

class MyPub : public Pub
{
public:
    void initOrder() override {}
    std::vector<Beer> getBeers() override { return {Beer(),Beer()}; }
    void generateBill() override {}
};

%}
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251