Question

I have some code like below:

class SingleValue
{
public:
   SingleValue()
   {}

   ~SingleValue()
   {}

   const std::string& getValue()const
   {
    return m_nSingleValue;
   }
private:
   int m_nSingleValue;
};

typedef SingleValue RoadType;
typedef SingleValue RoadSubType;
typedef SingleValue FunctionalClass;

now I want to use SWIG to generate a Java wrapper, But it generate only one proxy class 'SingleValue', I want to know how generate the other proxy class using swig, but I can't find some relative information after googling.

I try %rename, but it only generate one proxy class, not three.

Was it helpful?

Solution

What you're trying to achieve seems to be strong typing. SWIG by default tries to expose an interface with the same behaviours as you would see in C++, so in that case the behaviour is expected - weak typedefs are all C++ offers. You can work around this though.

Given the header file:

#include <string>

class SingleValue
{
public:
   SingleValue()
   {}

   ~SingleValue()
   {}

   std::string getValue() const
   {
      return std::to_string(m_nSingleValue);
   }
private:
   int m_nSingleValue;
};

typedef SingleValue RoadType;
typedef SingleValue RoadSubType;
typedef SingleValue FunctionalClass;

inline RoadType make_road() { return RoadType(); }
FunctionalClass make_func() { return FunctionalClass(); }

which differs from yours only in the corrections to getValue() and the addition of two inline functions for testing we can wrap it and get close to strong typedef semantics by doing:

%module test

%{
#include "test.h"
%}

%include <std_string.i>

class SingleValue
{
public:
   SingleValue();
   ~SingleValue();
   std::string getValue() const;
};

struct RoadType : public SingleValue {
};

struct RoadSubType : public SingleValue {
};

struct FunctionalClass : public SingleValue {
};

RoadType make_road();
FunctionalClass make_func();

Notice that I've not shown SWIG the typedef at all and I've lied completely about the type and existance of RoadType etc., but this is OK like that because all the code that gets generated by SWIG is legal and correct still.

This cause an interface to be generated where the make_X functions return distinct types.


If you wanted to avoid the duplication between the header file and the interface file you could introduce a macro to help, the header file becomes:

#include <string>

class SingleValue
{
public:
   SingleValue()
   {}

   ~SingleValue()
   {}

   std::string getValue() const
   {
      return std::to_string(m_nSingleValue);
   }
private:
   int m_nSingleValue;
};

#ifndef STRONG_TYPEDEF
#define STRONG_TYPEDEF(o,n) typedef o n
#endif

STRONG_TYPEDEF(SingleValue, RoadType);
STRONG_TYPEDEF(SingleValue, RoadSubType);
STRONG_TYPEDEF(SingleValue, FunctionalClass);

inline RoadType make_road() { return RoadType(); }
FunctionalClass make_func() { return FunctionalClass(); }

Which means the interface file can simply become:

%module test

%{
#include "test.h"
%}

%include <std_string.i>

#define STRONG_TYPEDEF(o, n) struct n : o {};

%include "test.h"

This works partly because SingleValue is a class so the strong typedef can become a sub-class in the Java type system for it to enforce checking on. If the type isn't a class you can still do the same thing without using inheritance, for example the first part of an answer I gave on a similar problem using D would work - you'd want to elaborate on the empty structs though if there isn't any inheritance in play.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top