swig: расширение шаблона класса для обеспечения __str__
Скажем, у вас есть шаблонный класс Foo
, и вы хотите его прозрачно обернуть Swig, чтобы вы могли напечатать класс:
>>> from example import * >>> f = Foo2() >>> print(f) In Foo class!
Я следил за этим сообщением и этим . Поэтому мой заголовочный файл:
#include <iostream> template <int d> class Foo { public: friend std::ostream &operator<<(std::ostream &os, const Foo &m) { os << "Inside Foo class!" << std::endl; return os; } };
И мой файл интерфейса:
%{ #include <sstream> #include <iostream> #include "foo.hpp" %} %include "std_iostream.i" // Try grabbing it unmodified %include "foo.hpp" /* Instantiate a few different versions of the template */ %template(Foo2) Foo<2>; %template(Foo3) Foo<3>; %extend Foo<2> { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } };
Так что это работает очень хорошо, я могу напечатать объект по-прежнему, но я хотел бы обобщить его для любого значения параметра шаблона, так как нет смысла копировать этот код для каждого параметра шаблона. Я попробовал следующее в файле интерфейса, но это не сработало:
template <int d> class Foo { public: %extend { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } } };
- Различия в контурах между C ++ и Python
- Использование SWIG для переноса C ++ для Python. «вектор» не объявлен
- Как запустить программу на C и получить выход из программы с помощью Twisted Python
- Эффективное обновление таблицы SQLite со многими записями
- Метод без возвращаемого значения в модуле расширения python c
Вы должны иметь возможность %extend
основной шаблон, вне его определения, опустив список параметров шаблона:
%extend Foo { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } }; %template(Foo2) Foo<2>; %template(Foo3) Foo<3>;
Или вы можете использовать макрос SWIG для переноса и расширения каждой специализации за один раз:
%define WRAP_FOO(N) %template( Foo ## N ) Foo<N>; %extend Foo<N> { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } }; %enddef /* Instantiate a few different versions of the template */ WRAP_FOO(2) WRAP_FOO(3)
Обратите внимание, что в любом случае вы вызываете неопределенное поведение, возвращая результат .c_str()
std::string
которая уничтожается до возвращения функции.
Синтаксис %extend
вы используете в своем последнем примере, должен быть правильным, это метод, который мы используем в OpenStudio
Я считаю, что проблема в том, что вы определяете шаблон 2 раза, один раз в своей директиве %import
и один раз в своем .i
файле. Первое определение – это то, которое использует SWIG.
Хотя это и не идеально, я считаю, что вам нужно будет отбросить директиву %include "foo.hpp"
и определить конкретный интерфейс, который вы хотите. Ваш новый .i
файл теперь станет чем-то вроде:
%{ #include <sstream> #include <iostream> #include "foo.hpp" %} %include "std_iostream.i" // Don't let SWIG directly parse foo.hpp // %include "foo.hpp" template <int d> class Foo { public: // include here prototypes for all functions // you want exposed. You don't need the implementation like in // a normal C++ template declaration // include here any extensions you want to add %extend { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } } }; /* Instantiate a few different versions of the template */ %template(Foo2) Foo<2>; %template(Foo3) Foo<3>;
Кроме того, вы можете поместить код SWIG в свой файл hpp напрямую и сохранить необходимость поддерживать два API:
Новый .i-файл:
%{ #include <sstream> #include <iostream> #include "foo.hpp" %} %include "std_iostream.i" // let swig directly parse foo.hpp %include "foo.hpp" /* Instantiate a few different versions of the template */ %template(Foo2) Foo<2>; %template(Foo3) Foo<3>;
Новый .hpp-файл:
#include <iostream> template <int d> class Foo { public: #ifdef SWIG %extend { const char *__str__() { std::ostringstream oss(std::ostringstream::out); oss << *self; return oss.str().c_str(); } } #endif friend std::ostream &operator<<(std::ostream &os, const Foo &m) { os << "Inside Foo class!" << std::endl; return os; } };
- Можно ли использовать библиотеку C с python AppEngine?
- Измените имя класса модуля в SWIG
- Фильтрация каталогов при разборе файлов cpp в get-include в python bindings / clang
- Редактор для кода Python в .NET Application
- Algo для поиска дубликатов в очень большом массиве
- Ускорение процесса сборки с distutils
- Почему вывод subprocess.run отличается от вывода shell той же команды?
- Идентифицировать разговорный язык в аудиофайлах
- C struct в Python