Search code examples
c++templatesluavariadic-templatesswig

How can I wrap a variadic template member function of a variadic template class in SWIG?


I have a header file containing the definition of a variadic template, which also contains a few variadic templated member functions. Code snippets below have been significantly simplified and cut down for brevity:

#pragma once

template<typename T, typename ... CtorArgs>
class Foo {
public:
  Foo(CtorArgs... args) : _m(args...) {}

  template<typename ... Args>
  void DoSomething(Args... args) { _m.DoSomething(args...); }
private:
  T _m;
};

I then have another header defining a class to be used in a template specialization:

#pragma once

#include <string>
#include <iostream>

class Bar {
public:
  Bar(std::string const & a,
      std::string const & b) :
        m_strA(a),
        m_strB(b) {}

  void DoSomething(int const one, int const two) {
    std::cout << "Str A: " << m_strA << ", Str B: "<<  m_strB << ", ints: " << one << ", " << two << std::endl;
  }

private:
  std::string m_strA;
  std::string m_strB;
};

I would like to wrap the Foo specialization using SWIG, as well as its templated member function, so I can use them from a Lua script.

The problem I am encountering is that SWIG is not generating a wrapper for the DoSomething templated function as I expect.

After reading some of the SWIG documentation, I am aware that it is unable to use the %template directive with more than 1 substitution for the parameter pack arguments, so I have used %rename instead:

%module FooSwig
%include <std_string.i>

%{
#include "foo.hpp"
#include "bar.hpp"
%}

%include "foo.hpp"
%include "bar.hpp"

%rename(lua_foo) Foo<Bar, std::string const &, std::string const &>;
class Foo<Bar, std::string const &, std::string const &> {
public:
  Foo(std::string const &, std::string const &);

  template<typename ... Args>
  void DoSomething(Args... args);
private:
  Bar _m;
};

Using the %template directive doesn't work (as expected), as there are more than 1 parameters to substitute - I get the following from swig:

Error: Template 'DoSomething' undefined.

I imagine I need to get around this using %rename again, but I can't figure out how. I've tried the following:

%extend Foo<Bar, std::string const &, std::string const &>
{
  %rename(Do_Something) DoSomething<int const, int const>;
  void DoSomething(int const, int const);
}

And that does generate something, but the wrapper contains a symbol for a function that is undefined:

Foo_Sl_Bar_Sc_std_string_SS_const_SA__Sc_std_string_SS_const_SA__Sg__DoSomething(arg1,arg2,arg3);

instead of the expected call to a member function template, something along the lines of

(arg1)->SWIGTEMPLATEDISAMBIGUATOR DoSomething<int const, int const>(arg2, arg3);

I'm running out of things to try, and maybe one of you can help?

Some info about my environment: I'm using g++ 7.4.0, c++ 17 and SWIG 3.0.


Solution

  • I managed to get the wrapper generated and it works as expected.

    This is a snippet of the old SWIG interface file:

    ...
      template<typename ... Args>
      void DoSomething(Args... args);
    ...
    

    I replaced it with the following:

    ...
      void DoSomething(int const, int const);
    ...
    

    However I am still curious to find out whether there is a better way to do it so any further info (or pointers to reading materials/source code) would be appreciated.