开发者

Export template function

开发者 https://www.devze.com 2023-02-17 14:19 出处:网络
what\'s the right way to export template function from c++ into python using boost.python? Here is the code:

what's the right way to export template function from c++ into python using boost.python? Here is the code:

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

And usage:

    print GetValue("width")
Boost.Python.ArgumentError: Python argument types in
    GetValue(ConfigManager, str)
did not matc开发者_C百科h C++ signature:
    GetValue(ConfigManager {lvalue}, std::string, int)

What's wrong?


You should read the relevant Boost documentation regarding default arguments. I'll summarize below.


The problem here is that default arguments are used when calling functions in C++. Get rid of them and you'll see the problem from Python's perspective:

// 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

The fundamental issue is that function types don't carry default argument information. So how can we simulate it? Essentially, by overloading:

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

A maintenance hassle. Luckily, Boost makes this easy:

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

The macro also exists for class members. This is in the documentation, if any of it is unclear.


You can also add another template for your class so that you don't have to write/instantiate for each int/float type.

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号