В boost-python для некоторого класса X рекомендуется использовать виртуальный метод, как показано ниже.
Я пытаюсь объединить это с функциональностью, чтобы указать параметры по умолчанию для этого виртуального метода. Это также поддерживается в документации Boost.
Однако не приведен пример использования виртуального метода, который также имеет параметры по умолчанию.
Я предположил, что класс-обертка должен также определить аргумент в качестве значения по умолчанию и передать его базовому getItem()
.
Аргумент по умолчанию - NULL-указатель, хотя у меня нет оснований подозревать (пока), что это актуально.
struct X_wrap : X, wrapper<X>
{
X_wrap(): X() {}
// getItem() is a non-Pure Virtual Function in Class X
// It has a single argument a, which has a default value of 1
A* getItem(Z* a=NULL)
{
if (override getItem = this->get_override("getItem"))
return getItem(a);
return X::getItem(a);
}
A* default_getItem(Z* a=NULL) { return this->X::getItem(a); }
};
Это тогда определяется как:
.def("getItem",
&X::getItem,
&X_wrap::default_getItem);
Проблема в том, что параметр по умолчанию не будет переноситься как часть сигнатуры метода.
Boost предоставляет обходной путь для этого:
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getItem_member_overloads, getItem, 0, 1)
В невиртуальном случае ясно, как применить это к def
:
.def("getItem",
&X::getItem,
getItem_member_overloads());
Компилируется и работает как положено.
Однако, поскольку обертка и функция по умолчанию усложняют ситуацию, когда у нас есть виртуальная функция, не ясно, как их объединить. Я предполагаю, что вышеупомянутое не может быть правильным решением, так как я удалил default_getItem()
из определения.
Это побудило меня попытаться создать второй набор перегрузок:
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(default_getItem_overloads, default_getItem, 0, 1);
Макрос компилируется, но, кажется, не существует способа применить 2 отдельных набора перегрузок к .def()
, который затем не завершится компиляцией.
Google предложил использовать boost::python::arg()
и определить его как arg("a")=1
:
Что-то вроде приведенных ниже компиляций:
.def("getItem",
&X::getItem,
arg("a")=0,
&X_wrap::default_getItem,
arg("a")=0);
Но я получаю ошибку во время выполнения:
Boost.Python.ArgumentError: Python argument types in
X.getItem(ChildClassOfX)
did not match C++ signature:
getItem(X_wrap {lvalue}, Z* a=0)
getItem(X {lvalue}, Z* a=0)
Это говорит о том, что ChildClassOfX
по какой-то причине не соответствует сигнатуре getItem()
в базовом классе X
.
На данный момент я немного офигеваю - и мои определения, вероятно, просты и неверны!
Пока что любое решение, которое у меня есть, либо каким-то образом нарушает полиморфизм времени выполнения, либо не компилируется.
Любые предложения или примеры будут огромной помощью!
(Примечание для Чистые Виртуальные функции. Отсутствие требования для функции по умолчанию означает, что в .def()
передается только одна функция, так что легко изменить не виртуальный тривиальный пример - это дело не в не чистых виртуалах)
EDIT
Нашел в сети одну ссылку на кого-то, кто задает тот же вопрос - решение близко к моей попытке использовать аргументы, но, похоже, не работает и идет вразрез с текущей документацией Boost? Он использует класс-обертку в def()
как для getItem()
, так и default_getItem()
с одним переданным набором аргументов - ниже приведен пример, приведенный в ссылке. Единственное другое отличие - это значение по умолчанию, а не указатель, как в моем случае:
def("override", WrapperClass::func, WrapperClass::default_func, (arg("x"), arg("y")=0, arg("z")=false))
Модификация для моего примера сборки в порядке, но выдает:
Boost.Python.ArgumentError: Python argument types in
X.getItem(ChildClassOfX)
did not match C++ signature:
getItem(X_wrap {lvalue}, Z* a=0)
getItem(X_wrap {lvalue}, Z* a=0)
Ссылка:
http://boost.2283326.n4.nabble.com/Boost-Python-inheritance-optional-parameters-td4592869.html