Wrap derived template class with Boost::python
Question: 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 to define a class wrapper for each base class ? Have I to
define a class wrapper for each type used into my template class ?

Thank you for your helpful answers


Answer: The `RuntimeError` occurs because a requirement for the
[`class_`](http://www.boost.org/doc/libs/1_55_0/libs/python/doc/v2/class.html#class_-
spec)'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](http://www.boost.org/doc/libs/1_55_0/libs/python/doc/v2/class.html#footnote_1)
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)
    

