接受并执行函数中的不同函数作为参数

时间:2015-12-03 16:23:53

标签: c++ templates c++11 lambda function-pointers

在使用Armadillo库时我发现在处理缺失值时存在一个循环模式。例如,如果我想对矩阵的行执行var操作并处理缺失值,我会像这样继续

void varianceRows(const mat& M,vec& v)
{
    for(uint i=0;i<M.n_rows;i++)     // variance calculated on rows
    {
        if(M.row(i).is_finite())
            v(i) = var(M.row(i));
        else if(!any(M.row(i)>0))
            v(i) = NAN;
        else
        {
            vec b=M.row(i);
            v(i) = var(b.elem(find_finite(b)));
        }
    }
}

现在我意识到通常情况下执行相同的程序但具有不同的功能(例如meanmediansum等。我当时想知道如何编写这个函数的泛型版本,以便它可以接受不同的函数作为参数。我现在的尝试是:

template<typename Func>
void FuncOnMat(const mat& M,vec& v,Func func)
{
    for(uint i=0;i<M.n_rows;i++)     // operation calculated on rows
    {
        if(M.row(i).is_finite())
            v(i) = func(M.row(i));
        else if(!any(M.row(i)>0))
            v(i) = NAN;
        else
        {
            vec b=M.row(i);
            v(i) = func(b.elem(find_finite(b)));
        }
    }
} 

但是当我执行

 FuncOnMat(A,r,mean);

它不起作用。我觉得我需要提供一个仿函数或lambda。哪种方法最好?

2 个答案:

答案 0 :(得分:0)

我认为在这种情况下你应该使用函数指针作为第三个参数而不是模板,只有当你的矩阵类可以是不同的类型时,你可能需要使用模板,通常用模板来构建多个执行的函数对不同类型的操作相同,它们在COMPILE时工作,而不是运行时,因此functor / lambda / function指针不能是模板参数。

这是一个带有函数指针的解决方案,也可以与lambda一起使用。

因为在你的例子中没有关于M和v中使用的类型的线索,所以使用&#34; float&#34;作为M和v的基本类型,但如果你使用double只需替换它......

>>> None == 0
False
>>> if not None:
...   print ("1")
...
1
>>>
>>> None == False
False
>>>

Lambda示例:

void FuncOnMat(const mat& M,vec& v,float (*func)(float))
{
  for(uint i=0;i<M.n_rows;i++)     // operation calculated on rows
  {
      if(M.row(i).is_finite())
        v(i) = func(M.row(i));
      else if(!any(M.row(i)>0))
          v(i) = NAN;
      else
      {
          vec b=M.row(i);
          v(i) = func(b.elem(find_finite(b)));
      }
  }
} 

答案 1 :(得分:0)

我认为你的想法是正确的,但与gabry的函数指针版本不同,模板版本需要FuncOnMat的定义在任何地方都可见。所以你可能会把它放在头文件中。

我把一个基于模板的快速示例放在一起,所有内容都塞进同一个文件中以保持简单。我使用std :: vector来模拟mat和vec类:

#include <vector>
#include <iostream>

using vec = std::vector<double>;
using mat = std::vector<vec>;

template <typename Func>
vec FuncOnMat(const mat& m, Func func) {
    vec v;
    for(const auto& row : m) {
        v.push_back(func(row));
    }
    return v;
}

// Mean is a functor which calculates a vec's elements' arithmetic mean
struct Mean {
    double operator ()(const vec& v) const {
        double sum = 0;
        for(double x : v) {
            sum += x;
        }
        return sum / v.size();
    }
};

// dumpvec prints the elements of a vec
void dumpvec(const vec& v) {
    for(auto x : v) {
        std::cout << x << "  ";
    }
    std::cout << "\n";
}

int main() {
    // define a matrix object
    mat m {{1, 2, 3}, {-3, 2, -1}, {0, 0, 0}};

    // use a functor object
    Mean mean_functor;
    vec  mean_vec = FuncOnMat(m, mean_functor);

    // use a lambda
    vec max_vec = FuncOnMat(m, [](const vec& v) {
        auto maxx = v.front();
        for(auto x : v) { if(x > maxx) { maxx = x; }} // yes, vec[0] checked redundantly
        return maxx;
    });

    // dump results
    std::cout << "Mean Functor: ";
    dumpvec(mean_vec);

    std::cout << "Max Lambda:   ";
    dumpvec(max_vec);
}