Frage

I have a derived class from a template class :

template<typename X, typename Y>
class BaseFunction
{
    static void export_BaseFunction()
    {
        ?????
    };
};
class Function : public BaseFunction<pair<double, double>, double>
{
    Function() : BaseFunction<pair<double, double>, double>() {};
    static void export_Function()
    {
    BaseFunction::export_BaseFunction();
    boost::python::class_<Function, boost::python::bases<BaseFunction<pair<double, double>, double>>, boost::shared_ptr<Function>>("Function");

    }
};

So Boost::Python asks me to create a class wrapper for BaseFunction but I don't find any information to write a template class, only template function.

Have I got to define a class wrapper for each base class? Have I to define a class wrapper for each type used into my template class?

War es hilfreich?

Lösung

The RuntimeError occurs because a requirement for the class_'s Bases template parameter is not being met:

A specialization of bases<...> which specifies previously-exposed C++ base classes of T

With previously-exposed being explained as:

namespace python = boost::python;
python::class_<Base>("Base");
python::class_<Derived, python::bases<Base> >("Derived");

To resolve the RuntimeError, either:

  • Omit the bases information if the exposed API does not need to perform upcasting or downcasting with Function and BaseFunction<...>. For example, if none of the C++ functions exposed to Python have a parameter type of BaseFunction<...> or return a Function object as a BaseFunction<...>&, then Boost.Python does not need to know about type relationship.
  • Otherwise, the base class needs to be exposed and Function needs to expose the relationship:

    namespace python = boost::python;
    typedef BaseFunction<pair<double, double>, double> function_base_type;
    python::class_<function_base_type>("Base");
    python::class_<Function, python::bases<function_base_type> >("Function");
    

    When registering the specific type instance of BaseFunction, the string identifier needs to be unique.


Below is a complete example that has Function expose BaseFunction. The export_BaseFunction() function will check if it has already been registered to prevent warning about duplicated conversions, and will use C++ type information name to disambiguate between different template instantiations of BaseFunction.

#include <utility>  // std::pair
#include <typeinfo> // typeid
#include <boost/python.hpp>

template<typename X, typename Y>
class BaseFunction
{
public:
  static void export_BaseFunction()
  {
    // If type is already registered, then return early.
    namespace python = boost::python;
    bool is_registered = (0 != python::converter::registry::query(
      python::type_id<BaseFunction>())->to_python_target_type());
    if (is_registered) return;

    // Otherwise, register the type as an internal type.
    std::string type_name = std::string("_") + typeid(BaseFunction).name();
    python::class_<BaseFunction>(type_name.c_str(), python::no_init);
  };
};

class Function
  : public BaseFunction<std::pair<double, double>, double>
{
private:

  typedef BaseFunction<std::pair<double, double>, double> parent_type;

public:

  static void export_Function()
  {
    // Explicitly register parent.
    parent_type::export_BaseFunction();
    // Expose this type and its relationship with parent.
    boost::python::class_<Function, boost::python::bases<parent_type>,
        boost::shared_ptr<Function> >("Function");
  }
};

/// @brief Example function to demonstrate upcasting.
void spam(BaseFunction<std::pair<double, double>, double>&) {}

BOOST_PYTHON_MODULE(example)
{
  Function::export_Function();
  boost::python::def("spam", &spam);
}

Interactive usage:

>>> import example
>>> f = example.Function()
>>> f
<example.Function object at 0xb7ec5464>
>>> example.spam(f)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top