1

I got an error while trying to generate a SWIG interface for a library I wanted to use. The code contains a class which inherits from a templated class, that include default values. However, the templated class also has a forward declaration that doesn't include defaults. I believe this is confusing swig.

Here's a simple example:

frac.h (parent class):

#pragma once

// forward declaration
template <typename A, typename B>
class Frac;

// ... code using the forward declaraton

// definition
template <typename A=int, typename B=int>
class Frac
{
public:
    A a;
    B b;

    double divide()
    {
        return a / b;
    };
};

timestwo.h (child class):

#pragma once

#include "frac.h"

class TimesTwo : public Frac<double>
{
public:
    double getValue()
    {
        a = 10.5;
        b = 4;

        return divide() * 2;
    }
};

mylib.i file:

%module mylib
 %{
 #include "timestwo.h"
 %}

%include "frac.h"

/*
If no %template is used:

mylib.h:15: Warning 401: Nothing known about base class 'Frac< double >'. Ignored.
mylib.h:15: Warning 401: Maybe you forgot to instantiate 'Frac< double >' using %template.
*/

/*
If put here: %template(frac_d) Frac <double>;

mylib.i:15: Error: Not enough template parameters specified. 2 required.
*/

/*
If put here: %template(frac_d) Frac <double, int>;

timestwo.h:5: Warning 401: Nothing known about base class 'Frac< double >'. Ignored.
timestwo.h:5: Warning 401: Maybe you forgot to instantiate 'Frac< double >' using %template.
*/

%include "timestwo.h"

As shown in the comments of mylib.i, I can't seem to instantiate the template correctly, since I need to use one template argument, but since the forward declaration doesn't specify the defaults, it says it's expecting two.

Stanley Bak
  • 543
  • 3
  • 16

1 Answers1

0

It's just a warning. Do you want to instantiate Frac or call divide? Otherwise, it works:

>>> import mylib
>>> t = mylib.TimesTwo()
>>> t.getValue()
5.25

If you want to be able to call divide(), SWIG doesn't seem to understand template defaults. It works by updating timestwo.h with Frac<double,int>, but if you don't want to modify the header, you can manually replicate the definition in the .i file with the correction:

%module mylib
%{
#include "timestwo.h"
%}

%include "frac.h"
%template(frac_d) Frac<double,int>; // Frac<double> doesn't work as of SWIG 3.0.12.

// Declare the interface the way SWIG likes it.
class TimesTwo : public Frac<double,int>
{
public:
    double getValue();
};

Demo:

>>> import mylib
>>> t = mylib.TimesTwo()
>>> t.getValue()
5.25
>>> t.divide()
2.625
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • Accepting as this works, but it's not ideal. The real `timestwo.h` is part of the library so I can't change it, and it includes lots of other definitions that are needed, so copying everything to this `.i` file is not ideal in case there are future changes. – Stanley Bak Nov 08 '18 at 19:13
  • @Stanley The Swig c++ parser isn’t up to the lastest standards, yet. – Mark Tolonen Nov 09 '18 at 06:07