1

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?

1 Answer 1

2

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)
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot for your explanation. It is very usefull for me. I understand better the relationship in Python/C++ A last question is : When a method returns a BaseType which I have not exposed into Python, I'm going to get an error. I have to expose the BaseType or whatever Type returned by a method ?
@Tux1 If you expose a function that has a return type of BaseType&, then BaseType needs to be exposed to Python as conversions will be necessary. If the object returned has a dynamic type of DerivedType, then DerivedType needs to be exposed and list BaseType as a base. Boost.Python will use the dynamic type to construct a DerivedType Python object, even though the function's return type is BaseType&.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.