使用boost.python将模板函数从c ++导出到python的正确方法是什么?这是代码:
template<typename T>
T getValue(const std::string &key, const T &defaultValue = T()) {}
// Export into some python class:
class_<ConfigManager>(...)
.def("GetValue", getValue<int>)
.def("GetValue", getValue<float>)
.def("GetValue", getValue<std::string>);
用法:
print GetValue("width")
Boost.Python.ArgumentError: Python argument types in
GetValue(ConfigManager, str)
did not match C++ signature:
GetValue(ConfigManager {lvalue}, std::string, int)
怎么了?
答案 0 :(得分:5)
您应该阅读有关默认参数的相关Boost documentation。我将在下面总结。
这里的问题是在C ++中调用函数时使用默认参数。摆脱它们,你会从Python的角度看问题:
// this function *must* be called with two parameters
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments!
.def("GetValue", getValue<float>) // Python has no idea about the defaults,
.def("GetValue", getValue<std::string>); // they are a C++ feature for calling
根本问题是函数类型不携带默认参数信息。那么我们如何模拟呢?基本上,通过重载:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
template<typename T>
T getValueDefault(const std::string &key)
{
// default available in C++,
// transitively available in Python
return getValue(key);
}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments
.def("GetValue", getValueDefault<int>) // one argument
// and so on
维护麻烦。幸运的是,Boost让这很容易:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
// creates utility class x, which creates overloads of function y,
// with argument count as low as a and as high as b:
// BOOST_PYTHON_FUNCTION_OVERLOADS(x, y, a, b);
BOOST_PYTHON_FUNCTION_OVERLOADS(getValueIntOverloads, getValue<int>, 1, 2);
class_<ConfigManager>(...)
.def("GetValue", getValue<int>, getValueIntOverloads()) // one or two arguments
// and so on
宏也存在于类成员中。如果有任何不明确的内容,请参阅文档。
答案 1 :(得分:0)
您还可以为您的类添加另一个模板,这样您就不必为每个int / float类型编写/实例化。
template<typename LinksT>
class Base {
public:
virtual ~Base() {}
virtual Base* x() = 0;
};
#include <boost/python.hpp>
using namespace boost::python;
template<typename LinksT>
class BaseWrap : public Base<LinksT>, public wrapper<Base<LinksT> > {
public:
virtual Base<LinksT>* x() { return this->get_override("x")(); }
};
template<typename LinksT>
void export_virtualfunction()
{
class_<BaseWrap<LinksT>, boost::noncopyable>("Base", no_init)
.def("x", pure_virtual(&Base<LinksT>::x), return_internal_reference<>())
;
}
BOOST_PYTHON_MODULE(test_template_python)
{
export_virtualfunction<int>();
}