如何在C ++中轻松地将函数应用于集合

时间:2009-02-26 02:54:51

标签: c++ templates mapreduce

我将图像存储为数组,根据其元素的类型进行模板化,例如Image<unsigned>Image<float>等。我经常需要对这些图像执行操作;例如,我可能需要添加两个图像,或平方图像(元素),依此类推。所有操作都是元素化的。我希望尽可能接近写下这样的内容:

float Add(float a, float b) { return a+b; }
Image<float> result = Add(img1, img2);

甚至更好,像

complex ComplexCombine(float a, float b) { return complex(a, b); }
Image<complex> result = ComplexCombine(img1, img2);

struct FindMax {
    unsigned currentMax;
    FindMax(): currentMax(0) {}
    void operator(unsigned a) { if(a > currentMax) currentMax = a; }
};

FindMax findMax;
findMax(img);
findMax.currentMax;  // now contains the maximum value of 'img'

现在,我显然无法做到这一点;我写了一些东西,以便我可以打电话:

Image<float> result = Apply(img1, img2, Add);

但我似乎无法找出一种通用的方法来检测传递的函数/函数对象的返回类型,所以上面的ComplexCombine示例已经出来了;另外,我必须为每个我想传递的论点写一个新的(这似乎是不可避免的)。

关于如何实现这一点的任何想法(尽可能少的样板代码)?

2 个答案:

答案 0 :(得分:3)

这就是他STL中的unary_function,binary_function等类型具有result_type typedef的原因。如果你使用std :: ptr_fun,你可以利用Apply,

来利用它

e.g。

template<typename Func, typename Arg, typename Result = Func::result_type>
Image<Result> Apply(Arg a1, Arg a2, Func f) {
        return Image<Result>(f(a1,a2));
}

而且,

Apply(img1, img2, std::ptr_fun(&Add));

好的,你抓住了我,我没有测试过。它仍然可能,但更多的工作,而无法直接使用某些STL功能

#include <iostream>

template<typename T>
struct Image {
  T val_;
  Image(const T& val) : val_(val) {}
};

template<typename Arg1, typename Arg2, typename Result>
struct image_fun_adapter {
  Result (*f)(Arg1, Arg2);
  Image<Result> operator()(const Image<Arg1>& a1, const Image<Arg2>& a2) {
    return Image<Result>(f(a1.val_, a2.val_));
  }
};

template<typename Arg1, typename Arg2, typename Result>
image_fun_adapter<Arg1,Arg2,Result> image_fun_ptr(Result (*f)(Arg1,Arg2)) {
  image_fun_adapter<Arg1,Arg2,Result> rv;
  rv.f = f;
  return rv;
}

float Add(float a, float b) { return a + b; }

int main() {
  Image<float> a(1.0);
  Image<float> b(12.5);
  // this is the cute bit:
  Image<float> c = image_fun_ptr(&Add)(a,b);

  std::cout << c.val_ << std::endl;
  return 0;
}

答案 1 :(得分:1)

模板专业化!

template<typename T>
T Add(const T &left, const T &right)
{
    return left + right;
}

template<typename T>
struct AddTwo
{
    T operator()(const T &left, const T &right)
    {
        return Add(left, right);
    }
};

// something like this (not exactly sure)
template<std::vector<typename V>>
std::vector<V> Add(const std::vector<V> &left, const std::vector<V> &right)
{
    assert(left.size() == right.size());

    std::vector ret(left.size());

    std::transform(left.const_begin(), left.const_end(), right.const_begin(), ret.begin(), AddTwo());

    return ret;
}