我将图像存储为数组,根据其元素的类型进行模板化,例如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
示例已经出来了;另外,我必须为每个我想传递的论点写一个新的(这似乎是不可避免的)。
关于如何实现这一点的任何想法(尽可能少的样板代码)?
答案 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;
}