2011-03-18 122 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>(); 
}