Reputation: 2830
In many examples about boost::python you see something like:
using namespace boost::python;
typedef class_<std::vector<float>> VectorFloat;
And then of course if you need a double
vector you will have a second class called DoubleVector
or so.
In my opinion this is not very "pythonic". It would be more intuitive (I think), if one (templated) class in C++ is actually one class in python which takes an argument like , ..., type='float', ... ,
. This way the class also appears only once in the pydocs and has to be added only once to the boost::python module
.
So let's say we have a simple templated class for our C++ code:
template <typename T>
MyClass
{
T val;
public:
MyClass(const T& tVal) : val(tVal) {}
T getVal() { return val; }
void setVal(const T& tVal) { val = tVal; }
};
Now we want to write an interface for Python. My idea so far:
Using boost::variant
typedef boost::variant<MyClass<float>, MyClass<double>> VariantClass;
class MyPythonClass
{
VariantClass vClass;
public:
MyPythonClass(
const PyObject& tVal,
const boost::python::str& type)
{
using namespace boost::python;
std::string type_string = extract<std::string>(type);
if( type_string == "float" )
{
float f = extract<float>(tVal);
vClass = MyClass(f);
}
else if( type_string == "double" )
{
double d = extract<double>(tVal);
vClass = MyClass(d);
}
}
boost::python::PyObject* getVal()
{
// What to put here?
}
void setVal(const boost::python::PyObject& tVal)
{
//What to put here?
}
};
BOOST_PYTHON_MODULE(my_module)
{
class_<MyPythonClass>("MyClass", init<boost::python::PyObject, int, boost::python::str>).def("getVal", &MyClass::getVal());
}
A clear drawback of this solution is I guess that boost::variant can work with types that are quite different wheras my classes are almost identitcal, except for the type of data they store. So probably more information is abstracted away than necessary.
So the question I guess boils down to the two empty functions in the example. However, cleaner and shorter or less "if"-chain like answers will of course also be accepted. As the title says, it is about templated classes and boost::python and not necessarily about boost::variant.
Upvotes: 0
Views: 828
Reputation: 303017
There's a couple sources of confusion here. First, in Python, object
is already basically a variant - everything is an object
. And in C++, a class template isn't a type - it's a recipe for creating a type. So if you want to expose MyClass<T>
from C++ to Python, you should just expose all the MyClass<T>s
I would write a function template that does the bindings:
template <class T>
void bind_MyClass(const char* name) {
class_<MyClass<T>>(name, init<T const&>())
.add_property("val", &MyClass<T>::getVal, &MyClass<T>::setVal);
;
}
And then just call it:
bind_MyClass<float>("MyClassFloat");
bind_MyClass<double>("MyClassDouble");
Upvotes: 1