如何用swig为Python包装一个跟随可调用特征的模板化函数?

时间:2017-09-21 08:11:48

标签: c++ c++11 templates swig

我有一个C ++类,其模板的方法是遵循可调用的特性:

// 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?
    }
};

这里,MyOptimizationAlgorithm类实现了一种优化算法。用户提供数据对象(双精度矢量,此处没有问题)和目标函数。此功能是优化算法所依赖的用户可配置部分。例如,有效的可调用评估器可以实现Ackley的功能,交叉托盘功能等。

模式实际上非常标准:在C ++中,可调用/谓词特征允许我模拟方法,以便我可以传递Functor或std::function。如,

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) { /* ... */ });

我现在想用swig为Python创建一个包装器。当然,目标是在Python中创建赋值器函子并将其传递给C ++例程,如下所示:

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())

我是swig的新手。我已经收集到我需要专门化模板(使用%template)并且我需要创建一个导演(%director)。我试图创建一个Functor包装器,如下所示:

%inline %{
    struct MyEvaluator
    {
        virtual double operator()(MyObject const& o) { return 0.0; }
        virtual ~MyEvaluator() {}
    };
%}

%feature("director") MyEvaluator;
%extend MyAlgorithm {
    %template(runPredicated) optimize<MyEvaluator>;
}

我曾希望我可以在Python中创建我的Functor的子类,在那里定义__call__并使用它,但它只调用MyEvaluator::operator(),这是毫无意义的(并且可以理解,因为我专门用于使用MyEvaluator)的模板。

那么:我需要在接口文件中添加什么来利用Python中C ++代码的可调用特性?

1 个答案:

答案 0 :(得分:0)

这有点太通用了。如果你想限制自己使用std :: function接口,比如

class MyOptimizationAlgorithm
{
// ...
public:

    // An optimization function that uses a user-supplied 
    // callable to evaluate a data object:
    template<typename T>
    void optimize(MyObject o, std::function<T(MyObject const&)> evaluator) {
          // ... optimize, optimize, ...
          T value = evaluator(o);
          // ... are we good enough yet?
    }
};

可能的包装器看起来像

class MyOptimizationAlgorithm:
  def `optimize<double>` as optimize(o: MyObject, evaluator: (o: MyObject)->float)

并且可以使用任何Python函数调用MyObject并返回一个float。问题中的Python代码应该可以正常工作。

上面的包装器是PyCLIF(而不是SWIG)。