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 ofT
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 withFunction
andBaseFunction<...>
. For example, if none of the C++ functions exposed to Python have a parameter type ofBaseFunction<...>
or return aFunction
object as aBaseFunction<...>&
, 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)