I have a C++ class with a method that is templated to follow the callable trait:
// A general data object
struct MyObject
{
// ... hold some data, parameters, ...
};
class MyOptimizationAlgorithm
{
// ...
public:
// An optimization function that uses a user-supplied
// callable to evaluate a data object:
template <class Callable> void optimize(MyObject o, Callable evaluator) {
// ... optimize, optimize, ...
auto value = evaluator(o);
// ... are we good enough yet?
}
};
Here, the MyOptimizationAlgorithm
class implements an optimization algorithm. The user supplies a data object (a vector of doubles, no problem here) and an objective function. This function is the user-configurable part on which the optimization algorithm relies. For example, valid callable evaluators could implement Ackley's function, the Cross-in Tray function, etc.
The pattern is actually pretty standard: In C++, the callable/predicate trait allows me to template a method so that I can pass a Functor, or a std::function
. E.g.,
struct Ackley
{
double operator()(MyObject const& o)
{
return /* ackley() applied to the values in o */
}
};
MyOptimizationAlgorithm optimizer;
MyObject initialData;
// ... supply data,
// ... tune some parameters of the optimizer, then:
optimizer.optimize(initialData, Ackley());
// ... or:
optimizer.optimize(initalData, [](MyObject const& o) { /* ... */ });
I would now like to create a wrapper for Python with swig. The goal is, of course, to create the evaluator functor in Python and pass it to the C++ routine, like so:
def CrossInTray:
def __call__(self, obj):
# calculate the cross-in tray function.
optimzer = MyOptimizationAlgorithm()
initial_data = MyObject()
# ... again, setup, then:
optimizer.optimize(initial_data, CrossInTray())
I am new to swig. I have gathered that I need to specialize the template (using %template
) and that I need to create a director (%director
). I have tried to create a Functor wrapper, like so:
%inline %{
struct MyEvaluator
{
virtual double operator()(MyObject const& o) { return 0.0; }
virtual ~MyEvaluator() {}
};
%}
%feature("director") MyEvaluator;
%extend MyAlgorithm {
%template(runPredicated) optimize<MyEvaluator>;
}
I had hoped that I could then create subclasses of my Functor in Python, define __call__
there and have it used, but it only calls MyEvaluator::operator()
, which is pretty pointless (and understandable, since I specialized the template to use MyEvaluator
).
So: What do I need to add to the interface file to make use of the callable trait of C++ code in Python?