Проблема здесь в том, что каждый раз, когда вы создаете шаблон в C ++, вам нужна как минимум одна директива %template
в вашем интерфейсе SWIG, чтобы она могла влиять на сгенерированную оболочку.
Когда люди смутно намекают на то, что std::enable_if
работает, они обычно означают две вещи. Во-первых, это нормально, а во-вторых, что %template
работает для них. Обе вещи верны здесь.
Поскольку вы использовали SFINAE внутри класса вашего шаблона с функцией шаблона, вам нужно одно %template
для каждого. В противном случае, как вы видели, элемент set
полностью игнорируется. Боковой шаг по биту SFINAE / enable_if по вашему вопросу пример шаблонных функций внутри шаблонных классов - хорошее место для начала.
Так что мы можем изменить ваш .i файл, чтобы он выглядел примерно так:
%module test
%{
#include "test.h"
%}
%include "test.h"
// Be explicit about what 'versions' of set to instantiate in our wrapper
%template(set) Handle::set<false, void>;
%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;
Проблема в том, что (исправив несколько незначительных ошибок в нем) ваш тестовый питон теперь нажимает «this not print», потому что мы сгенерировали (полностью допустимую) функцию set()
даже в случае const явно расшифровка параметров шаблона вместо их вывода.
Итак, мы сгенерировали код для вызова:
Handle<true>::set<false, void>(int);
Что работает в этом случае, потому что он может компилироваться, но не интуитивно понятным способом.
Я не знаю, как здесь можно сделать вывод (это позор, потому что они по умолчанию, так что должно быть возможно, верно? - Может быть, один для патча в ствол SWIG хотя сделать дефолт и SFINAE будет сложно)
К счастью, существует простой обходной путь, использующий %ignore
для удаления версии, которая нам тоже не нужна:
% тест модуля
%{
#include "test.h"
%}
%include "test.h"
%template(set) Handle::set<false, void>;
%ignore Handle<true>::set;
%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;
Который затем генерирует ожидаемый код.
Стоит отметить, что зачастую проще явно указать, как нужно, чтобы сложный шаблонный код работал при генерации оболочек - вам обычно нужны дополнительные помощники или настройки интерфейса, чтобы заставить его работать в Python так, как вы надеетесь на , Таким образом, вы также можете решить свой пример, выполнив что-то вроде этого:
%module test
%{
#include "test.h"
%}
template <bool>
class Handle {
public:
Handle(void);
Handle(int value);
int get(void) const;
};
template<>
class Handle<false>
{
public:
Handle(void);
Handle(int value);
void set(int value);
int get(void) const;
};
%template(NonConstHandle) Handle<false>;
%template(ConstHandle) Handle<true>;
Или подобный трюк:
%module test
%{
#include "test.h"
typedef Handle<true> ConstHandle;
typedef Handle<false> NonConstHandle;
%}
struct ConstHandle {
ConstHandle(void);
ConstHandle(int value);
int get(void) const;
};
struct NonConstHandle
{
NonConstHandle(void);
NonConstHandle(int value);
void set(int value);
int get(void) const;
};
Хотя обратите внимание, что в этом последнем случае вам также нужно будет использовать %apply
, если вы хотите использовать шаблоны в качестве аргументов в / из функций.