2011-03-18 84 views
2

使用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

在什么范围是getValue?它是一个类成员函数还是静态方法? – zdan 2011-03-18 20:39:31

+0

@zdan是其班级成员。我隐瞒了这部分,以获得更少的代码。 – Ockonal 2011-03-18 20:45:27

回答

4

有关默认参数,您应该阅读相关的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 

该宏也存在于类成员中。这是在文件中,如果有任何不清楚的话。

+0

感谢您的好评! – Ockonal 2011-03-18 21:14:58

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>(); 
}