Обертка Swig для наследования классов от специализированного типа шаблона приводит к отсутствию методов - PullRequest
0 голосов
/ 29 марта 2020

Я использую Swig 1.4.1, чтобы обернуть некоторый код C ++ для проекта C#.
Рассмотрим следующий код, который находится в одном файле Foo.h .

#ifndef __Foo__
#define __Foo__

namespace Ogre
{
    template<int foo, typename T> class FooBase
    {
    public:

        int getFooBase() const
        {
            return 1;
        }
    };

    struct FooSpecialized : public FooBase<4, double>
    {
        int getFooSpecialized() const
        {
            return 2;
        }
    };

    class FooImpl : public FooSpecialized
    {
    public:
        int getFooImpl() const
        {
            return 3;
        }
    };
}

#endif

Для этого я использую следующее в своем файле интерфейса Swig.

%include "Foo.h"

В результате я получаю доступ к методам getFooSpecialized() и getFooImpl(). Но getFooBase() отсутствует.

Я получаю без предупреждений при компиляции моего файла интерфейса Swig.

Это можно легко увидеть, посмотрев созданные файлы C# , Существует один файл FooSpecialized.cs , который содержит

public class FooSpecialized : global::System.IDisposable {
  ...

  public int getFooFooSpecialized() {
    int ret = OgrePINVOKE.FooSpecialized_getFooFooSpecialized(swigCPtr);
    if (OgrePINVOKE.SWIGPendingException.Pending) throw OgrePINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }
}

и FooImpl.cs , который содержит

public class FooImpl : FooSpecialized {
  ...

  public int getFooImpl() {
    int ret = OgrePINVOKE.FooImpl_getFooImpl(swigCPtr);
    if (OgrePINVOKE.SWIGPendingException.Pending) throw OgrePINVOKE.SWIGPendingException.Retrieve();
    return ret;
  }
}

Я пробовал %rename и %template пока, но это не работает. Я также читал о разделении файла, но это не вариант для меня, потому что это сторонний компонент, с которым я работаю.

1 Ответ

1 голос
/ 01 апреля 2020

Ключом является использование и позиция %template. Используйте ваш Foo.h как есть, работает следующий файл test.i:

%module test

%{
#include "Foo.h"    // Adds Foo.h to the generated code.
%}

// Declare to SWIG the FooBase class interface.
namespace Ogre
{
    template<int foo, typename T> class FooBase
    {
    public:
        int getFooBase() const;
    };

// Now that SWIG knows the template, declare an instantiation of
// the template you want to use.
%template(FooBase4dbl) FooBase<4,double>;

// Declare the class interfaces that uses the template instance

    struct FooSpecialized : public FooBase<4, double>
    {
        int getFooSpecialized() const;
    };

    class FooImpl : public FooSpecialized
    {
    public:
        int getFooImpl() const;
    };
}

Если вы хотите, вы можете реорганизовать заголовок, чтобы уменьшить дублирование кода:

FooBase.h

#ifndef __FooBase__
#define __FooBase__

namespace Ogre
{
    template<int foo, typename T> class FooBase
    {
    public:
        int getFooBase() const
        {
            return 1;
        }
    };
}

#endif

Foo.h

#ifndef __Foo__
#define __Foo__

#include "FooBase.h"

namespace Ogre
{
    struct FooSpecialized : public FooBase<4, double>
    {
        int getFooSpecialized() const
        {
            return 2;
        }
    };

    class FooImpl : public FooSpecialized
    {
    public:
        int getFooImpl() const
        {
            return 3;
        }
    };
}

#endif

test.i

%module test

%{
#include "Foo.h"
%}

%include "FooBase.h"
%template(FooSpec) Ogre::FooBase<4,double>;
%include "Foo.h"

Демонстрация (я настроен на Python):

>>> import test
>>> f=test.FooImpl()
>>> f.getFooBase()
1
...